From 248b689749d75852051812215b34d88eed19dce0 Mon Sep 17 00:00:00 2001 From: Wassim Bougarfa <12980387+wassimoo@users.noreply.github.com> Date: Wed, 25 Feb 2026 10:31:57 +0100 Subject: [PATCH 1/7] feat: add rate limits table with search option --- data/bucket-to-endpoints-20260204-1941.csv | 186 ++++++++++++ data/bucket-to-threshold-20260204-1941.csv | 232 +++++++++++++++ docs/guides/rate-limits.mdx | 8 +- docusaurus.config.ts | 1 + src/components/RateLimitsTable/index.tsx | 265 ++++++++++++++++++ src/components/RateLimitsTable/types.ts | 24 ++ src/lib/rate-limits/csv-provider.ts | 98 +++++++ .../bucket-to-endpoints-20260204-1941.csv | 186 ++++++++++++ .../bucket-to-threshold-20260204-1941.csv | 232 +++++++++++++++ src/lib/rate-limits/index.ts | 14 + src/lib/rate-limits/provider.ts | 25 ++ src/lib/rate-limits/types.ts | 69 +++++ .../docusaurus-rate-limits-data/index.ts | 28 ++ src/static/rate-limits.json | 1 + src/theme/MDXComponents.js | 2 + 15 files changed, 1369 insertions(+), 2 deletions(-) create mode 100644 data/bucket-to-endpoints-20260204-1941.csv create mode 100644 data/bucket-to-threshold-20260204-1941.csv create mode 100644 src/components/RateLimitsTable/index.tsx create mode 100644 src/components/RateLimitsTable/types.ts create mode 100644 src/lib/rate-limits/csv-provider.ts create mode 100644 src/lib/rate-limits/data/bucket-to-endpoints-20260204-1941.csv create mode 100644 src/lib/rate-limits/data/bucket-to-threshold-20260204-1941.csv create mode 100644 src/lib/rate-limits/index.ts create mode 100644 src/lib/rate-limits/provider.ts create mode 100644 src/lib/rate-limits/types.ts create mode 100644 src/plugins/docusaurus-rate-limits-data/index.ts create mode 100644 src/static/rate-limits.json diff --git a/data/bucket-to-endpoints-20260204-1941.csv b/data/bucket-to-endpoints-20260204-1941.csv new file mode 100644 index 0000000000..971df21cc3 --- /dev/null +++ b/data/bucket-to-endpoints-20260204-1941.csv @@ -0,0 +1,186 @@ +Method,Path,Bucket +GET,/.well-known/jwks.json,hydra-public-low +GET,/.well-known/openid-configuration,hydra-public-low +GET,/.well-known/ory/webauthn.js,hydra-public-low +GET,/admin/clients,hydra-admin-medium +POST,/admin/clients,hydra-admin-high +GET,/admin/clients/{id},hydra-admin-low +DELETE,/admin/clients/{id},hydra-admin-high +PATCH,/admin/clients/{id},hydra-admin-high +PUT,/admin/clients/{id},hydra-admin-high +HEAD,/.well-known/openid-configuration,hydra-public-low +PUT,/admin/clients/{id}/lifespans,hydra-admin-high +GET,/admin/keys/{set},hydra-admin-medium +DELETE,/admin/keys/{set},hydra-admin-high +POST,/admin/keys/{set},hydra-admin-high +PUT,/admin/keys/{set},hydra-admin-high +GET,/admin/keys/{set}/{kid},hydra-admin-medium +DELETE,/admin/keys/{set}/{kid},hydra-admin-high +PUT,/admin/keys/{set}/{kid},hydra-admin-high +GET,/admin/oauth2/auth/requests/consent,hydra-admin-low +PUT,/admin/oauth2/auth/requests/consent/accept,hydra-admin-low +PUT,/admin/oauth2/auth/requests/consent/reject,hydra-admin-low +PUT,/admin/oauth2/auth/requests/device/accept,hydra-admin-low +GET,/admin/oauth2/auth/requests/login,hydra-admin-low +PUT,/admin/oauth2/auth/requests/login/accept,hydra-admin-low +PUT,/admin/oauth2/auth/requests/login/reject,hydra-admin-low +GET,/admin/oauth2/auth/requests/logout,hydra-admin-low +PUT,/admin/oauth2/auth/requests/logout/accept,hydra-admin-low +PUT,/admin/oauth2/auth/requests/logout/reject,hydra-admin-low +GET,/admin/oauth2/auth/sessions/consent,hydra-admin-low +DELETE,/admin/oauth2/auth/sessions/consent,hydra-admin-high +DELETE,/admin/oauth2/auth/sessions/login,hydra-admin-high +POST,/admin/oauth2/introspect,hydra-admin-low +DELETE,/admin/oauth2/tokens,hydra-admin-high +GET,/admin/trust/grants/jwt-bearer/issuers,hydra-admin-medium +POST,/admin/trust/grants/jwt-bearer/issuers,hydra-admin-high +GET,/admin/trust/grants/jwt-bearer/issuers/{id},hydra-admin-medium +DELETE,/admin/trust/grants/jwt-bearer/issuers/{id},hydra-admin-high +OPTIONS,/admin/clients,hydra-admin-low +OPTIONS,/admin/clients/{id},hydra-admin-low +POST,/credentials,hydra-admin-medium +GET,/oauth2/auth,hydra-public-medium +HEAD,/oauth2/auth,hydra-public-low +POST,/oauth2/device/auth,hydra-public-low +GET,/oauth2/device/verify,hydra-admin-low +OPTIONS,/oauth2/auth,hydra-public-low +POST,/oauth2/register,hydra-public-high +GET,/oauth2/register/{id},hydra-admin-low +DELETE,/oauth2/register/{id},hydra-public-high +PUT,/oauth2/register/{id},hydra-public-high +POST,/oauth2/revoke,hydra-public-medium +GET,/oauth2/sessions/logout,hydra-public-medium +POST,/oauth2/auth,hydra-public-medium +POST,/oauth2/token,hydra-public-medium +GET,/oauth2/consent,hydra-public-low +GET,/oauth2/fallbacks/logout/callback,hydra-public-low +POST,/oauth2/sessions/logout,hydra-public-medium +OPTIONS,/oauth2/token,hydra-public-low +GET,/userinfo,hydra-public-medium +DELETE,/admin/relation-tuples,keto-admin-high +PATCH,/admin/relation-tuples,keto-admin-high +PUT,/admin/relation-tuples,keto-admin-high +GET,/namespaces,keto-admin-high +POST,/opl/syntax/check,keto-admin-medium +POST,/ory.keto.relation_tuples.v1alpha2.CheckService/BatchCheck,keto-public-low +POST,/ory.keto.relation_tuples.v1alpha2.CheckService/Check,keto-public-low +POST,/ory.keto.relation_tuples.v1alpha2.WriteService/TransactRelationTuples,keto-admin-high +GET,/relation-tuples,keto-admin-medium +POST,/relation-tuples/batch/check,keto-public-low +GET,/relation-tuples/check,keto-public-low +POST,/relation-tuples/check,keto-public-low +GET,/relation-tuples/check/openapi,keto-public-low +POST,/relation-tuples/check/openapi,keto-public-low +GET,/relation-tuples/expand,keto-admin-medium +GET,/admin/courier/messages,kratos-admin-high +PATCH,/admin/identities,kratos-admin-high +POST,/admin/identities,kratos-admin-high +DELETE,/admin/identities/{id},kratos-admin-high +PATCH,/admin/identities/{id},kratos-admin-high +PUT,/admin/identities/{id},kratos-admin-high +DELETE,/admin/identities/{id}/credentials/{type},kratos-admin-high +DELETE,/admin/identities/{id}/sessions,kratos-admin-high +POST,/admin/recovery/code,kratos-admin-high +POST,/admin/recovery/link,kratos-admin-high +DELETE,/admin/sessions/{id},kratos-admin-high +PATCH,/admin/sessions/{id}/extend,kratos-admin-high +POST,/scim/{client}/v2/Groups,kratos-admin-high +PUT,/scim/{client}/v2/Groups/{id},kratos-admin-high +PATCH,/scim/{client}/v2/Groups/{id},kratos-admin-high +DELETE,/scim/{client}/v2/Groups/{id},kratos-admin-high +POST,/scim/{client}/v2/Users,kratos-admin-high +PUT,/scim/{client}/v2/Users/{id},kratos-admin-high +PATCH,/scim/{client}/v2/Users/{id},kratos-admin-high +DELETE,/scim/{client}/v2/Users/{id},kratos-admin-high +GET,/admin/identities/{id},kratos-admin-low +GET,/admin/sessions/{id},kratos-admin-low +OPTIONS,/admin/identities/{id},kratos-admin-low +GET,/admin/courier/messages/{id},kratos-admin-medium +GET,/admin/identities,kratos-admin-medium +GET,/admin/identities/{id}/sessions,kratos-admin-medium +GET,/admin/identities/by/external/{externalID},kratos-admin-medium +GET,/admin/sessions,kratos-admin-medium +GET,/schemas,kratos-admin-medium +GET,/schemas/{id},kratos-admin-medium +GET,/scim/{client}/v2/Groups,kratos-admin-medium +GET,/scim/{client}/v2/Groups/{id},kratos-admin-medium +GET,/scim/{client}/v2/Schemas,kratos-admin-medium +GET,/scim/{client}/v2/Schemas/{id},kratos-admin-medium +GET,/scim/{client}/v2/ServiceProviderConfig,kratos-admin-medium +GET,/scim/{client}/v2/Users,kratos-admin-medium +GET,/scim/{client}/v2/Users/{id},kratos-admin-medium +GET,/self-service/errors,kratos-public-low +GET,/self-service/fed-cm/parameters,kratos-public-low +POST,/self-service/fed-cm/token,kratos-public-high +POST,/self-service/login,kratos-public-high +GET,/self-service/login/api,kratos-public-medium +GET,/self-service/login/browser,kratos-public-medium +GET,/self-service/login/flows,kratos-public-low +HEAD,/self-service/fed-cm/parameters,kratos-public-low +GET,/self-service/logout,kratos-public-low +OPTIONS,/self-service/fed-cm/token,kratos-public-low +DELETE,/self-service/logout/api,kratos-public-medium +GET,/self-service/logout/browser,kratos-public-medium +GET,/self-service/login,kratos-public-low +OPTIONS,/self-service/login,kratos-public-low +GET,/self-service/methods/oidc/callback/{provider_id},kratos-public-medium +GET,/self-service/methods/oidc/organizations/{organization_id},kratos-public-medium +GET,/self-service/methods/saml/callback/{provider_id},kratos-public-medium +GET,/self-service/methods/saml/organizations/{organization_id},kratos-public-medium +POST,/self-service/recovery,kratos-public-high +HEAD,/self-service/login/browser,kratos-public-low +OPTIONS,/self-service/login/browser,kratos-public-low +POST,/self-service/login/browser,kratos-public-medium +GET,/self-service/recovery/api,kratos-public-medium +GET,/self-service/recovery/browser,kratos-public-medium +OPTIONS,/self-service/login/flows,kratos-public-low +GET,/self-service/recovery/flows,kratos-public-low +OPTIONS,/self-service/logout,kratos-public-low +POST,/self-service/registration,kratos-public-high +OPTIONS,/self-service/logout/browser,kratos-public-low +GET,/self-service/methods/oidc/callback,kratos-public-low +GET,/self-service/registration/api,kratos-public-medium +GET,/self-service/registration/browser,kratos-public-medium +GET,/self-service/registration/flows,kratos-public-low +POST,/self-service/settings,kratos-public-high +HEAD,/self-service/methods/oidc/callback/{provider_id},kratos-public-low +GET,/self-service/recovery,kratos-public-low +GET,/self-service/settings/api,kratos-public-medium +GET,/self-service/settings/browser,kratos-public-medium +GET,/self-service/settings/flows,kratos-public-low +POST,/self-service/verification,kratos-public-high +HEAD,/self-service/recovery,kratos-public-low +OPTIONS,/self-service/recovery,kratos-public-low +HEAD,/self-service/recovery/browser,kratos-public-low +GET,/self-service/verification/api,kratos-public-medium +GET,/self-service/verification/browser,kratos-public-medium +OPTIONS,/self-service/recovery/browser,kratos-public-low +GET,/self-service/verification/flows,kratos-public-low +OPTIONS,/self-service/recovery/flows,kratos-public-low +GET,/sessions,kratos-public-medium +DELETE,/sessions,kratos-public-high +DELETE,/sessions/{id},kratos-public-high +GET,/sessions/token-exchange,kratos-public-medium +GET,/self-service/registration,kratos-public-low +OPTIONS,/self-service/registration,kratos-public-low +HEAD,/self-service/registration/browser,kratos-public-low +GET,/sessions/whoami,kratos-public-low +OPTIONS,/self-service/registration/browser,kratos-public-low +GET,/self-service/settings,kratos-public-low +OPTIONS,/self-service/settings,kratos-public-low +GET,/self-service/verification,kratos-public-low +HEAD,/self-service/verification,kratos-public-low +OPTIONS,/self-service/verification,kratos-public-low +HEAD,/self-service/verification/browser,kratos-public-low +OPTIONS,/self-service/verification/flows,kratos-public-low +OPTIONS,/sessions,kratos-public-low +GET,/saml/.well-known/idp-metadata,polis-public-low +GET,/saml/.well-known/saml.cer,polis-public-low +GET,/saml/.well-known/sp-metadata,polis-public-low +GET,/saml/api/error,polis-public-low +POST,/saml/api/identity-federation/sso,polis-public-medium +GET,/saml/api/identity-federation/sso,polis-public-medium +POST,/saml/api/oauth/authorize,polis-public-medium +GET,/saml/api/oauth/authorize,polis-public-medium +GET,/saml/api/oauth/oidc,polis-public-medium +POST,/saml/api/oauth/saml,polis-public-medium diff --git a/data/bucket-to-threshold-20260204-1941.csv b/data/bucket-to-threshold-20260204-1941.csv new file mode 100644 index 0000000000..adb0db5576 --- /dev/null +++ b/data/bucket-to-threshold-20260204-1941.csv @@ -0,0 +1,232 @@ +bucketname,tier,env,rpm,rps +hydra-admin-high,Develop,dev,20,2 +hydra-admin-high,Develop,prod,20,2 +hydra-admin-high,Develop,stage,20,2 +hydra-admin-high,Enterprise,dev,40,3 +hydra-admin-high,Enterprise,prod,320,10 +hydra-admin-high,Enterprise,stage,40,3 +hydra-admin-high,Growth,dev,40,3 +hydra-admin-high,Growth,prod,160,7 +hydra-admin-high,Growth,stage,40,3 +hydra-admin-high,Production,dev,40,3 +hydra-admin-high,Production,prod,80,4 +hydra-admin-high,Production,stage,40,3 +hydra-admin-low,Develop,dev,40,3 +hydra-admin-low,Develop,prod,40,3 +hydra-admin-low,Develop,stage,40,3 +hydra-admin-low,Enterprise,dev,80,4 +hydra-admin-low,Enterprise,dev,80,4 +hydra-admin-low,Enterprise,prod,4800,160 +hydra-admin-low,Enterprise,prod,18000,600 +hydra-admin-low,Enterprise,stage,80,4 +hydra-admin-low,Enterprise,stage,80,4 +hydra-admin-low,Growth,dev,80,4 +hydra-admin-low,Growth,prod,2400,80 +hydra-admin-low,Growth,stage,80,4 +hydra-admin-low,Production,dev,80,4 +hydra-admin-low,Production,prod,250,10 +hydra-admin-low,Production,stage,80,4 +hydra-admin-medium,Develop,dev,20,2 +hydra-admin-medium,Develop,prod,20,2 +hydra-admin-medium,Develop,stage,20,2 +hydra-admin-medium,Enterprise,dev,40,3 +hydra-admin-medium,Enterprise,prod,320,10 +hydra-admin-medium,Enterprise,stage,40,3 +hydra-admin-medium,Growth,dev,40,3 +hydra-admin-medium,Growth,prod,160,7 +hydra-admin-medium,Growth,stage,40,3 +hydra-admin-medium,Production,dev,40,3 +hydra-admin-medium,Production,prod,80,4 +hydra-admin-medium,Production,stage,40,3 +hydra-public-high,Develop,dev,20,2 +hydra-public-high,Develop,prod,20,2 +hydra-public-high,Develop,stage,20,2 +hydra-public-high,Enterprise,dev,40,3 +hydra-public-high,Enterprise,prod,320,10 +hydra-public-high,Enterprise,stage,40,3 +hydra-public-high,Growth,dev,40,3 +hydra-public-high,Growth,prod,160,7 +hydra-public-high,Growth,stage,40,3 +hydra-public-high,Production,dev,40,3 +hydra-public-high,Production,prod,80,4 +hydra-public-high,Production,stage,40,3 +hydra-public-low,Develop,dev,60,3 +hydra-public-low,Develop,prod,60,3 +hydra-public-low,Develop,stage,60,3 +hydra-public-low,Enterprise,dev,120,7 +hydra-public-low,Enterprise,prod,1500,55 +hydra-public-low,Enterprise,stage,120,7 +hydra-public-low,Growth,dev,120,7 +hydra-public-low,Growth,prod,720,30 +hydra-public-low,Growth,stage,120,7 +hydra-public-low,Production,dev,120,7 +hydra-public-low,Production,prod,250,10 +hydra-public-low,Production,stage,120,7 +hydra-public-medium,Develop,dev,40,3 +hydra-public-medium,Develop,prod,40,3 +hydra-public-medium,Develop,stage,40,3 +hydra-public-medium,Enterprise,dev,80,4 +hydra-public-medium,Enterprise,dev,80,4 +hydra-public-medium,Enterprise,prod,3000,100 +hydra-public-medium,Enterprise,prod,3500,120 +hydra-public-medium,Enterprise,stage,80,4 +hydra-public-medium,Enterprise,stage,80,4 +hydra-public-medium,Growth,dev,80,4 +hydra-public-medium,Growth,prod,1000,35 +hydra-public-medium,Growth,stage,80,4 +hydra-public-medium,Production,dev,80,4 +hydra-public-medium,Production,prod,320,10 +hydra-public-medium,Production,stage,80,4 +keto-admin-high,Develop,dev,60,3 +keto-admin-high,Develop,prod,60,3 +keto-admin-high,Develop,stage,60,3 +keto-admin-high,Enterprise,dev,120,7 +keto-admin-high,Enterprise,prod,1000,35 +keto-admin-high,Enterprise,stage,120,7 +keto-admin-high,Growth,dev,120,7 +keto-admin-high,Growth,prod,250,10 +keto-admin-high,Growth,stage,120,7 +keto-admin-high,Production,dev,120,7 +keto-admin-high,Production,prod,250,10 +keto-admin-high,Production,stage,120,7 +keto-admin-medium,Develop,dev,100,5 +keto-admin-medium,Develop,prod,100,5 +keto-admin-medium,Develop,stage,100,5 +keto-admin-medium,Enterprise,dev,200,10 +keto-admin-medium,Enterprise,prod,2000,70 +keto-admin-medium,Enterprise,stage,200,10 +keto-admin-medium,Growth,dev,200,10 +keto-admin-medium,Growth,prod,1000,35 +keto-admin-medium,Growth,stage,200,10 +keto-admin-medium,Production,dev,200,10 +keto-admin-medium,Production,prod,500,20 +keto-admin-medium,Production,stage,200,10 +keto-public-low,Develop,dev,120,7 +keto-public-low,Develop,prod,120,7 +keto-public-low,Develop,stage,120,7 +keto-public-low,Enterprise,dev,240,10 +keto-public-low,Enterprise,prod,18000,600 +keto-public-low,Enterprise,stage,240,10 +keto-public-low,Growth,dev,240,10 +keto-public-low,Growth,prod,9000,300 +keto-public-low,Growth,stage,240,10 +keto-public-low,Production,dev,240,10 +keto-public-low,Production,prod,1500,55 +keto-public-low,Production,stage,240,10 +kratos-admin-high,Develop,dev,100,5 +kratos-admin-high,Develop,prod,100,5 +kratos-admin-high,Develop,stage,100,5 +kratos-admin-high,Enterprise,dev,200,10 +kratos-admin-high,Enterprise,prod,2400,80 +kratos-admin-high,Enterprise,stage,200,10 +kratos-admin-high,Growth,dev,200,10 +kratos-admin-high,Growth,dev,200,10 +kratos-admin-high,Growth,prod,1200,45 +kratos-admin-high,Growth,prod,3500,120 +kratos-admin-high,Growth,stage,200,10 +kratos-admin-high,Growth,stage,200,10 +kratos-admin-high,Production,dev,200,10 +kratos-admin-high,Production,prod,400,15 +kratos-admin-high,Production,stage,200,10 +kratos-admin-low,Develop,dev,100,5 +kratos-admin-low,Develop,prod,100,5 +kratos-admin-low,Develop,stage,100,5 +kratos-admin-low,Enterprise,dev,200,10 +kratos-admin-low,Enterprise,dev,200,10 +kratos-admin-low,Enterprise,prod,2400,80 +kratos-admin-low,Enterprise,prod,6000,200 +kratos-admin-low,Enterprise,stage,200,10 +kratos-admin-low,Enterprise,stage,200,10 +kratos-admin-low,Growth,dev,200,10 +kratos-admin-low,Growth,prod,1200,45 +kratos-admin-low,Growth,stage,200,10 +kratos-admin-low,Production,dev,200,10 +kratos-admin-low,Production,prod,400,15 +kratos-admin-low,Production,stage,200,10 +kratos-admin-medium,Develop,dev,50,3 +kratos-admin-medium,Develop,prod,50,3 +kratos-admin-medium,Develop,stage,50,3 +kratos-admin-medium,Enterprise,dev,100,5 +kratos-admin-medium,Enterprise,prod,800,30 +kratos-admin-medium,Enterprise,stage,100,5 +kratos-admin-medium,Growth,dev,100,5 +kratos-admin-medium,Growth,dev,100,5 +kratos-admin-medium,Growth,prod,400,15 +kratos-admin-medium,Growth,prod,1000,35 +kratos-admin-medium,Growth,stage,100,5 +kratos-admin-medium,Growth,stage,100,5 +kratos-admin-medium,Production,dev,100,5 +kratos-admin-medium,Production,prod,200,10 +kratos-admin-medium,Production,stage,100,5 +kratos-public-high,Develop,dev,50,3 +kratos-public-high,Develop,prod,50,3 +kratos-public-high,Develop,stage,50,3 +kratos-public-high,Enterprise,dev,100,5 +kratos-public-high,Enterprise,prod,1200,45 +kratos-public-high,Enterprise,stage,100,5 +kratos-public-high,Growth,dev,100,5 +kratos-public-high,Growth,dev,100,5 +kratos-public-high,Growth,prod,600,25 +kratos-public-high,Growth,prod,1200,45 +kratos-public-high,Growth,stage,100,5 +kratos-public-high,Growth,stage,100,5 +kratos-public-high,Production,dev,100,5 +kratos-public-high,Production,prod,200,10 +kratos-public-high,Production,stage,100,5 +kratos-public-low,Develop,dev,200,10 +kratos-public-low,Develop,prod,200,10 +kratos-public-low,Develop,stage,200,10 +kratos-public-low,Enterprise,dev,400,15 +kratos-public-low,Enterprise,dev,400,15 +kratos-public-low,Enterprise,prod,21600,700 +kratos-public-low,Enterprise,prod,36000,1000 +kratos-public-low,Enterprise,stage,400,15 +kratos-public-low,Enterprise,stage,400,15 +kratos-public-low,Growth,dev,400,15 +kratos-public-low,Growth,dev,400,15 +kratos-public-low,Growth,prod,7200,240 +kratos-public-low,Growth,prod,21600,700 +kratos-public-low,Growth,stage,400,15 +kratos-public-low,Growth,stage,400,15 +kratos-public-low,Production,dev,400,15 +kratos-public-low,Production,prod,2400,80 +kratos-public-low,Production,stage,400,15 +kratos-public-medium,Develop,dev,100,5 +kratos-public-medium,Develop,prod,100,5 +kratos-public-medium,Develop,stage,100,5 +kratos-public-medium,Enterprise,dev,200,10 +kratos-public-medium,Enterprise,prod,1600,55 +kratos-public-medium,Enterprise,stage,200,10 +kratos-public-medium,Growth,dev,200,10 +kratos-public-medium,Growth,dev,200,10 +kratos-public-medium,Growth,prod,800,30 +kratos-public-medium,Growth,prod,4500,150 +kratos-public-medium,Growth,stage,200,10 +kratos-public-medium,Growth,stage,200,10 +kratos-public-medium,Production,dev,200,10 +kratos-public-medium,Production,prod,400,15 +kratos-public-medium,Production,stage,200,10 +polis-public-low,Develop,dev,15,2 +polis-public-low,Develop,prod,15,2 +polis-public-low,Develop,stage,15,2 +polis-public-low,Enterprise,dev,30,2 +polis-public-low,Enterprise,prod,250,10 +polis-public-low,Enterprise,stage,30,2 +polis-public-low,Growth,dev,30,2 +polis-public-low,Growth,prod,120,7 +polis-public-low,Growth,stage,30,2 +polis-public-low,Production,dev,30,2 +polis-public-low,Production,prod,60,3 +polis-public-low,Production,stage,30,2 +polis-public-medium,Develop,dev,60,3 +polis-public-medium,Develop,prod,60,3 +polis-public-medium,Develop,stage,60,3 +polis-public-medium,Enterprise,dev,120,7 +polis-public-medium,Enterprise,prod,1000,35 +polis-public-medium,Enterprise,stage,120,7 +polis-public-medium,Growth,dev,120,7 +polis-public-medium,Growth,prod,500,20 +polis-public-medium,Growth,stage,120,7 +polis-public-medium,Production,dev,120,7 +polis-public-medium,Production,prod,250,10 +polis-public-medium,Production,stage,120,7 diff --git a/docs/guides/rate-limits.mdx b/docs/guides/rate-limits.mdx index 03023cc3fb..8cdb86deed 100644 --- a/docs/guides/rate-limits.mdx +++ b/docs/guides/rate-limits.mdx @@ -47,9 +47,13 @@ To identify the rate limits that apply to your project: 1. Check your workspace subscription plan (Developer, Production, Growth, or Enterprise). 2. Identify the environment (Production, Staging, or Development) assigned to your project. -3. Refer to the tables below based on your subscription plan and project environment. +3. Use the interactive table below to filter by tier and environment, or search by API path to find which bucket and limits apply to a given endpoint. -### Rate limit tables by subscription plan +### Interactive rate limit tables + + + +### Rate limit tables by subscription plan (reference) #### Developer plan rate limits diff --git a/docusaurus.config.ts b/docusaurus.config.ts index a2a5663992..bd2416eb93 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -184,6 +184,7 @@ const config: Config = { ], "@docusaurus/plugin-content-pages", require.resolve("./src/plugins/docusaurus-polyfill"), + require.resolve("./src/plugins/docusaurus-rate-limits-data/index.ts"), // require.resolve("./src/plugins/docusaurus-static-fonts"), [ "@docusaurus/plugin-sitemap", diff --git a/src/components/RateLimitsTable/index.tsx b/src/components/RateLimitsTable/index.tsx new file mode 100644 index 0000000000..fdeba1d645 --- /dev/null +++ b/src/components/RateLimitsTable/index.tsx @@ -0,0 +1,265 @@ +// Copyright © 2022 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +import useBaseUrl from "@docusaurus/useBaseUrl" +import React, { useMemo, useState, useEffect } from "react" +import type { Env, RateLimitsData, Tier } from "./types" + +const TIERS: Tier[] = ["Developer", "Production", "Growth", "Enterprise"] +const ENVS: Env[] = ["Development", "Staging", "Production"] +const SEARCH_DEBOUNCE_MS = 250 + +function useRateLimitsData(): { + data: RateLimitsData | null + loading: boolean + error: string | null +} { + const baseUrl = useBaseUrl("rate-limits.json") + const [data, setData] = useState(null) + const [loading, setLoading] = useState(true) + const [error, setError] = useState(null) + + React.useEffect(() => { + setLoading(true) + setError(null) + fetch(baseUrl) + .then((res) => { + if (!res.ok) + throw new Error(`Failed to load rate limits: ${res.status}`) + return res.json() + }) + .then(setData) + .catch((e) => setError(e instanceof Error ? e.message : String(e))) + .finally(() => setLoading(false)) + }, [baseUrl]) + + return { data, loading, error } +} + +export interface RateLimitsTableProps { + /** Pre-select subscription tier (e.g. on tier subpages). */ + initialTier?: Tier + /** Pre-select project environment. */ + initialEnv?: Env +} + +export default function RateLimitsTable({ + initialTier = "Growth", + initialEnv = "Production", +}: RateLimitsTableProps): React.ReactElement { + const { data, loading, error } = useRateLimitsData() + const [tier, setTier] = useState(initialTier) + const [env, setEnv] = useState(initialEnv) + const [pathSearch, setPathSearch] = useState("") + const [pathSearchDebounced, setPathSearchDebounced] = useState("") + + useEffect(() => { + const t = setTimeout(() => setPathSearchDebounced(pathSearch), SEARCH_DEBOUNCE_MS) + return () => clearTimeout(t) + }, [pathSearch]) + + React.useEffect(() => { + setTier(initialTier) + setEnv(initialEnv) + }, [initialTier, initialEnv]) + + const filteredThresholds = useMemo(() => { + if (!data) return [] + return data.thresholds.filter((t) => t.tier === tier && t.env === env) + }, [data, tier, env]) + + const bucketToEndpoints = useMemo(() => { + if (!data) return new Map>() + const m = new Map>() + for (const e of data.endpoints) { + const list = m.get(e.bucket) ?? [] + list.push({ method: e.method, path: e.path }) + m.set(e.bucket, list) + } + return m + }, [data]) + + const searchQuery = pathSearchDebounced.trim().toLowerCase() + + const endpointMatchesSearch = useMemo(() => { + if (!searchQuery) return () => false + return (e: { method: string; path: string }) => + e.path.toLowerCase().includes(searchQuery) || + e.method.toLowerCase().includes(searchQuery) || + `${e.method} ${e.path}`.toLowerCase().includes(searchQuery) + }, [searchQuery]) + + const bucketsWithSearchMatch = useMemo(() => { + if (!searchQuery || !data) return null + const set = new Set() + for (const e of data.endpoints) { + if (endpointMatchesSearch(e)) set.add(e.bucket) + } + return set + }, [data, searchQuery, endpointMatchesSearch]) + + const displayedThresholds = useMemo(() => { + if (!bucketsWithSearchMatch) return filteredThresholds + return filteredThresholds.filter((t) => + bucketsWithSearchMatch.has(t.bucket), + ) + }, [filteredThresholds, bucketsWithSearchMatch]) + + if (loading) { + return ( +

+ Loading rate limits data… +

+ ) + } + if (error) { + return ( +

+ Error loading rate limits: {error} +

+ ) + } + if (!data) { + return ( +

+ No rate limits data available. +

+ ) + } + + return ( +
+
+ + + +
+ +
+

+ Thresholds by bucket ({tier} / {env}) + {searchQuery && ( + + (filtered by search) + + )} +

+
+ + + + + + + + + + + {displayedThresholds.map((t) => { + const endpoints = bucketToEndpoints.get(t.bucket) ?? [] + const maxEndpoints = searchQuery ? endpoints.length : 20 + const endpointsToShow = endpoints.slice(0, maxEndpoints) + const endpointDisplay = endpointsToShow.length + ? endpointsToShow.map((e) => { + const isMatch = endpointMatchesSearch(e) + return ( +
+ {e.path}{" "} + + ({e.method}) + +
+ ) + }) + : null + const overflow = + endpoints.length > maxEndpoints + ? endpoints.length - maxEndpoints + : 0 + return ( + + + + + + + ) + })} + +
+ Endpoint(s) + + Bucket + + Sustained (rpm) + + Burst (rps) +
+ {endpointDisplay} + {overflow > 0 && ( +
+ +{overflow} more +
+ )} +
+ {t.bucket} + + {t.rpm} + + {t.rps} +
+
+ {searchQuery && displayedThresholds.length === 0 && ( +

+ No buckets match the search "{pathSearchDebounced.trim()}". +

+ )} +
+
+ ) +} diff --git a/src/components/RateLimitsTable/types.ts b/src/components/RateLimitsTable/types.ts new file mode 100644 index 0000000000..56236727b1 --- /dev/null +++ b/src/components/RateLimitsTable/types.ts @@ -0,0 +1,24 @@ +// Copyright © 2022 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +export interface EndpointRow { + method: string + path: string + bucket: string +} + +export interface ThresholdRow { + bucket: string + tier: string + env: string + rpm: number + rps: number +} + +export interface RateLimitsData { + endpoints: EndpointRow[] + thresholds: ThresholdRow[] +} + +export type Tier = "Developer" | "Production" | "Growth" | "Enterprise" +export type Env = "Development" | "Staging" | "Production" diff --git a/src/lib/rate-limits/csv-provider.ts b/src/lib/rate-limits/csv-provider.ts new file mode 100644 index 0000000000..261f6fbce1 --- /dev/null +++ b/src/lib/rate-limits/csv-provider.ts @@ -0,0 +1,98 @@ +// Copyright © 2022 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +import * as fs from "fs" +import * as path from "path" +import type { EndpointRow, Env, GetThresholdsOptions, RateLimitsProvider, ThresholdRow, Tier } from "./types" +import { ENV_FROM_CSV, TIER_FROM_CSV } from "./types" + +const ENDPOINTS_CSV = "bucket-to-endpoints-20260204-1941.csv" +const THRESHOLDS_CSV = "bucket-to-threshold-20260204-1941.csv" + +/** + * Resolve data directory. When running from Docusaurus plugin, pass siteDir so paths resolve correctly. + */ +function getDataDir(siteDir?: string): string { + if (siteDir) { + return path.join(siteDir, "src", "lib", "rate-limits", "data") + } + return path.join(__dirname, "data") +} + +function parseCsv(content: string): string[][] { + const lines = content.trim().split(/\r?\n/) + return lines.map((line) => line.split(",").map((cell) => cell.trim())) +} + +/** + * For duplicate (bucket, tier, env) we keep the first row (CSV order). + */ +function dedupeThresholds(rows: ThresholdRow[]): ThresholdRow[] { + const key = (r: ThresholdRow) => `${r.bucket}|${r.tier}|${r.env}` + const seen = new Set() + return rows.filter((r) => { + const k = key(r) + if (seen.has(k)) return false + seen.add(k) + return true + }) +} + +export interface CsvProviderOptions { + /** Site directory (e.g. from Docusaurus plugin context) so CSV paths resolve correctly. */ + siteDir?: string +} + +export function createCsvProvider(options?: CsvProviderOptions): RateLimitsProvider { + const dataDir = getDataDir(options?.siteDir) + const endpointsPath = path.join(dataDir, ENDPOINTS_CSV) + const thresholdsPath = path.join(dataDir, THRESHOLDS_CSV) + + return { + async getEndpointsByBucket(): Promise { + const raw = fs.readFileSync(endpointsPath, "utf-8") + const rows = parseCsv(raw) + const [header, ...dataRows] = rows + if (!header || header[0] !== "Method" || header[1] !== "Path" || header[2] !== "Bucket") { + throw new Error(`Unexpected endpoints CSV header: ${header?.join(",")}`) + } + return dataRows + .filter((r) => r.length >= 3 && r[0] && r[1] && r[2]) + .map((r) => ({ method: r[0], path: r[1], bucket: r[2] })) + }, + + async getThresholds(options?: GetThresholdsOptions): Promise { + const raw = fs.readFileSync(thresholdsPath, "utf-8") + const rows = parseCsv(raw) + const [header, ...dataRows] = rows + if ( + !header || + header[0] !== "bucketname" || + header[1] !== "tier" || + header[2] !== "env" || + header[3] !== "rpm" || + header[4] !== "rps" + ) { + throw new Error(`Unexpected thresholds CSV header: ${header?.join(",")}`) + } + let result: ThresholdRow[] = dataRows + .filter((r) => r.length >= 5 && r[0] && r[1] && r[2]) + .map((r) => { + const tier = TIER_FROM_CSV[r[1]] ?? (r[1] as Tier) + const env = ENV_FROM_CSV[r[2]] ?? (r[2] as Env) + return { + bucket: r[0], + tier, + env, + rpm: parseInt(r[3], 10) || 0, + rps: parseInt(r[4], 10) || 0, + } + }) + result = dedupeThresholds(result) + if (options?.tier) result = result.filter((r) => r.tier === options.tier) + if (options?.env) result = result.filter((r) => r.env === options.env) + if (options?.bucket) result = result.filter((r) => r.bucket === options.bucket) + return result + }, + } +} diff --git a/src/lib/rate-limits/data/bucket-to-endpoints-20260204-1941.csv b/src/lib/rate-limits/data/bucket-to-endpoints-20260204-1941.csv new file mode 100644 index 0000000000..971df21cc3 --- /dev/null +++ b/src/lib/rate-limits/data/bucket-to-endpoints-20260204-1941.csv @@ -0,0 +1,186 @@ +Method,Path,Bucket +GET,/.well-known/jwks.json,hydra-public-low +GET,/.well-known/openid-configuration,hydra-public-low +GET,/.well-known/ory/webauthn.js,hydra-public-low +GET,/admin/clients,hydra-admin-medium +POST,/admin/clients,hydra-admin-high +GET,/admin/clients/{id},hydra-admin-low +DELETE,/admin/clients/{id},hydra-admin-high +PATCH,/admin/clients/{id},hydra-admin-high +PUT,/admin/clients/{id},hydra-admin-high +HEAD,/.well-known/openid-configuration,hydra-public-low +PUT,/admin/clients/{id}/lifespans,hydra-admin-high +GET,/admin/keys/{set},hydra-admin-medium +DELETE,/admin/keys/{set},hydra-admin-high +POST,/admin/keys/{set},hydra-admin-high +PUT,/admin/keys/{set},hydra-admin-high +GET,/admin/keys/{set}/{kid},hydra-admin-medium +DELETE,/admin/keys/{set}/{kid},hydra-admin-high +PUT,/admin/keys/{set}/{kid},hydra-admin-high +GET,/admin/oauth2/auth/requests/consent,hydra-admin-low +PUT,/admin/oauth2/auth/requests/consent/accept,hydra-admin-low +PUT,/admin/oauth2/auth/requests/consent/reject,hydra-admin-low +PUT,/admin/oauth2/auth/requests/device/accept,hydra-admin-low +GET,/admin/oauth2/auth/requests/login,hydra-admin-low +PUT,/admin/oauth2/auth/requests/login/accept,hydra-admin-low +PUT,/admin/oauth2/auth/requests/login/reject,hydra-admin-low +GET,/admin/oauth2/auth/requests/logout,hydra-admin-low +PUT,/admin/oauth2/auth/requests/logout/accept,hydra-admin-low +PUT,/admin/oauth2/auth/requests/logout/reject,hydra-admin-low +GET,/admin/oauth2/auth/sessions/consent,hydra-admin-low +DELETE,/admin/oauth2/auth/sessions/consent,hydra-admin-high +DELETE,/admin/oauth2/auth/sessions/login,hydra-admin-high +POST,/admin/oauth2/introspect,hydra-admin-low +DELETE,/admin/oauth2/tokens,hydra-admin-high +GET,/admin/trust/grants/jwt-bearer/issuers,hydra-admin-medium +POST,/admin/trust/grants/jwt-bearer/issuers,hydra-admin-high +GET,/admin/trust/grants/jwt-bearer/issuers/{id},hydra-admin-medium +DELETE,/admin/trust/grants/jwt-bearer/issuers/{id},hydra-admin-high +OPTIONS,/admin/clients,hydra-admin-low +OPTIONS,/admin/clients/{id},hydra-admin-low +POST,/credentials,hydra-admin-medium +GET,/oauth2/auth,hydra-public-medium +HEAD,/oauth2/auth,hydra-public-low +POST,/oauth2/device/auth,hydra-public-low +GET,/oauth2/device/verify,hydra-admin-low +OPTIONS,/oauth2/auth,hydra-public-low +POST,/oauth2/register,hydra-public-high +GET,/oauth2/register/{id},hydra-admin-low +DELETE,/oauth2/register/{id},hydra-public-high +PUT,/oauth2/register/{id},hydra-public-high +POST,/oauth2/revoke,hydra-public-medium +GET,/oauth2/sessions/logout,hydra-public-medium +POST,/oauth2/auth,hydra-public-medium +POST,/oauth2/token,hydra-public-medium +GET,/oauth2/consent,hydra-public-low +GET,/oauth2/fallbacks/logout/callback,hydra-public-low +POST,/oauth2/sessions/logout,hydra-public-medium +OPTIONS,/oauth2/token,hydra-public-low +GET,/userinfo,hydra-public-medium +DELETE,/admin/relation-tuples,keto-admin-high +PATCH,/admin/relation-tuples,keto-admin-high +PUT,/admin/relation-tuples,keto-admin-high +GET,/namespaces,keto-admin-high +POST,/opl/syntax/check,keto-admin-medium +POST,/ory.keto.relation_tuples.v1alpha2.CheckService/BatchCheck,keto-public-low +POST,/ory.keto.relation_tuples.v1alpha2.CheckService/Check,keto-public-low +POST,/ory.keto.relation_tuples.v1alpha2.WriteService/TransactRelationTuples,keto-admin-high +GET,/relation-tuples,keto-admin-medium +POST,/relation-tuples/batch/check,keto-public-low +GET,/relation-tuples/check,keto-public-low +POST,/relation-tuples/check,keto-public-low +GET,/relation-tuples/check/openapi,keto-public-low +POST,/relation-tuples/check/openapi,keto-public-low +GET,/relation-tuples/expand,keto-admin-medium +GET,/admin/courier/messages,kratos-admin-high +PATCH,/admin/identities,kratos-admin-high +POST,/admin/identities,kratos-admin-high +DELETE,/admin/identities/{id},kratos-admin-high +PATCH,/admin/identities/{id},kratos-admin-high +PUT,/admin/identities/{id},kratos-admin-high +DELETE,/admin/identities/{id}/credentials/{type},kratos-admin-high +DELETE,/admin/identities/{id}/sessions,kratos-admin-high +POST,/admin/recovery/code,kratos-admin-high +POST,/admin/recovery/link,kratos-admin-high +DELETE,/admin/sessions/{id},kratos-admin-high +PATCH,/admin/sessions/{id}/extend,kratos-admin-high +POST,/scim/{client}/v2/Groups,kratos-admin-high +PUT,/scim/{client}/v2/Groups/{id},kratos-admin-high +PATCH,/scim/{client}/v2/Groups/{id},kratos-admin-high +DELETE,/scim/{client}/v2/Groups/{id},kratos-admin-high +POST,/scim/{client}/v2/Users,kratos-admin-high +PUT,/scim/{client}/v2/Users/{id},kratos-admin-high +PATCH,/scim/{client}/v2/Users/{id},kratos-admin-high +DELETE,/scim/{client}/v2/Users/{id},kratos-admin-high +GET,/admin/identities/{id},kratos-admin-low +GET,/admin/sessions/{id},kratos-admin-low +OPTIONS,/admin/identities/{id},kratos-admin-low +GET,/admin/courier/messages/{id},kratos-admin-medium +GET,/admin/identities,kratos-admin-medium +GET,/admin/identities/{id}/sessions,kratos-admin-medium +GET,/admin/identities/by/external/{externalID},kratos-admin-medium +GET,/admin/sessions,kratos-admin-medium +GET,/schemas,kratos-admin-medium +GET,/schemas/{id},kratos-admin-medium +GET,/scim/{client}/v2/Groups,kratos-admin-medium +GET,/scim/{client}/v2/Groups/{id},kratos-admin-medium +GET,/scim/{client}/v2/Schemas,kratos-admin-medium +GET,/scim/{client}/v2/Schemas/{id},kratos-admin-medium +GET,/scim/{client}/v2/ServiceProviderConfig,kratos-admin-medium +GET,/scim/{client}/v2/Users,kratos-admin-medium +GET,/scim/{client}/v2/Users/{id},kratos-admin-medium +GET,/self-service/errors,kratos-public-low +GET,/self-service/fed-cm/parameters,kratos-public-low +POST,/self-service/fed-cm/token,kratos-public-high +POST,/self-service/login,kratos-public-high +GET,/self-service/login/api,kratos-public-medium +GET,/self-service/login/browser,kratos-public-medium +GET,/self-service/login/flows,kratos-public-low +HEAD,/self-service/fed-cm/parameters,kratos-public-low +GET,/self-service/logout,kratos-public-low +OPTIONS,/self-service/fed-cm/token,kratos-public-low +DELETE,/self-service/logout/api,kratos-public-medium +GET,/self-service/logout/browser,kratos-public-medium +GET,/self-service/login,kratos-public-low +OPTIONS,/self-service/login,kratos-public-low +GET,/self-service/methods/oidc/callback/{provider_id},kratos-public-medium +GET,/self-service/methods/oidc/organizations/{organization_id},kratos-public-medium +GET,/self-service/methods/saml/callback/{provider_id},kratos-public-medium +GET,/self-service/methods/saml/organizations/{organization_id},kratos-public-medium +POST,/self-service/recovery,kratos-public-high +HEAD,/self-service/login/browser,kratos-public-low +OPTIONS,/self-service/login/browser,kratos-public-low +POST,/self-service/login/browser,kratos-public-medium +GET,/self-service/recovery/api,kratos-public-medium +GET,/self-service/recovery/browser,kratos-public-medium +OPTIONS,/self-service/login/flows,kratos-public-low +GET,/self-service/recovery/flows,kratos-public-low +OPTIONS,/self-service/logout,kratos-public-low +POST,/self-service/registration,kratos-public-high +OPTIONS,/self-service/logout/browser,kratos-public-low +GET,/self-service/methods/oidc/callback,kratos-public-low +GET,/self-service/registration/api,kratos-public-medium +GET,/self-service/registration/browser,kratos-public-medium +GET,/self-service/registration/flows,kratos-public-low +POST,/self-service/settings,kratos-public-high +HEAD,/self-service/methods/oidc/callback/{provider_id},kratos-public-low +GET,/self-service/recovery,kratos-public-low +GET,/self-service/settings/api,kratos-public-medium +GET,/self-service/settings/browser,kratos-public-medium +GET,/self-service/settings/flows,kratos-public-low +POST,/self-service/verification,kratos-public-high +HEAD,/self-service/recovery,kratos-public-low +OPTIONS,/self-service/recovery,kratos-public-low +HEAD,/self-service/recovery/browser,kratos-public-low +GET,/self-service/verification/api,kratos-public-medium +GET,/self-service/verification/browser,kratos-public-medium +OPTIONS,/self-service/recovery/browser,kratos-public-low +GET,/self-service/verification/flows,kratos-public-low +OPTIONS,/self-service/recovery/flows,kratos-public-low +GET,/sessions,kratos-public-medium +DELETE,/sessions,kratos-public-high +DELETE,/sessions/{id},kratos-public-high +GET,/sessions/token-exchange,kratos-public-medium +GET,/self-service/registration,kratos-public-low +OPTIONS,/self-service/registration,kratos-public-low +HEAD,/self-service/registration/browser,kratos-public-low +GET,/sessions/whoami,kratos-public-low +OPTIONS,/self-service/registration/browser,kratos-public-low +GET,/self-service/settings,kratos-public-low +OPTIONS,/self-service/settings,kratos-public-low +GET,/self-service/verification,kratos-public-low +HEAD,/self-service/verification,kratos-public-low +OPTIONS,/self-service/verification,kratos-public-low +HEAD,/self-service/verification/browser,kratos-public-low +OPTIONS,/self-service/verification/flows,kratos-public-low +OPTIONS,/sessions,kratos-public-low +GET,/saml/.well-known/idp-metadata,polis-public-low +GET,/saml/.well-known/saml.cer,polis-public-low +GET,/saml/.well-known/sp-metadata,polis-public-low +GET,/saml/api/error,polis-public-low +POST,/saml/api/identity-federation/sso,polis-public-medium +GET,/saml/api/identity-federation/sso,polis-public-medium +POST,/saml/api/oauth/authorize,polis-public-medium +GET,/saml/api/oauth/authorize,polis-public-medium +GET,/saml/api/oauth/oidc,polis-public-medium +POST,/saml/api/oauth/saml,polis-public-medium diff --git a/src/lib/rate-limits/data/bucket-to-threshold-20260204-1941.csv b/src/lib/rate-limits/data/bucket-to-threshold-20260204-1941.csv new file mode 100644 index 0000000000..adb0db5576 --- /dev/null +++ b/src/lib/rate-limits/data/bucket-to-threshold-20260204-1941.csv @@ -0,0 +1,232 @@ +bucketname,tier,env,rpm,rps +hydra-admin-high,Develop,dev,20,2 +hydra-admin-high,Develop,prod,20,2 +hydra-admin-high,Develop,stage,20,2 +hydra-admin-high,Enterprise,dev,40,3 +hydra-admin-high,Enterprise,prod,320,10 +hydra-admin-high,Enterprise,stage,40,3 +hydra-admin-high,Growth,dev,40,3 +hydra-admin-high,Growth,prod,160,7 +hydra-admin-high,Growth,stage,40,3 +hydra-admin-high,Production,dev,40,3 +hydra-admin-high,Production,prod,80,4 +hydra-admin-high,Production,stage,40,3 +hydra-admin-low,Develop,dev,40,3 +hydra-admin-low,Develop,prod,40,3 +hydra-admin-low,Develop,stage,40,3 +hydra-admin-low,Enterprise,dev,80,4 +hydra-admin-low,Enterprise,dev,80,4 +hydra-admin-low,Enterprise,prod,4800,160 +hydra-admin-low,Enterprise,prod,18000,600 +hydra-admin-low,Enterprise,stage,80,4 +hydra-admin-low,Enterprise,stage,80,4 +hydra-admin-low,Growth,dev,80,4 +hydra-admin-low,Growth,prod,2400,80 +hydra-admin-low,Growth,stage,80,4 +hydra-admin-low,Production,dev,80,4 +hydra-admin-low,Production,prod,250,10 +hydra-admin-low,Production,stage,80,4 +hydra-admin-medium,Develop,dev,20,2 +hydra-admin-medium,Develop,prod,20,2 +hydra-admin-medium,Develop,stage,20,2 +hydra-admin-medium,Enterprise,dev,40,3 +hydra-admin-medium,Enterprise,prod,320,10 +hydra-admin-medium,Enterprise,stage,40,3 +hydra-admin-medium,Growth,dev,40,3 +hydra-admin-medium,Growth,prod,160,7 +hydra-admin-medium,Growth,stage,40,3 +hydra-admin-medium,Production,dev,40,3 +hydra-admin-medium,Production,prod,80,4 +hydra-admin-medium,Production,stage,40,3 +hydra-public-high,Develop,dev,20,2 +hydra-public-high,Develop,prod,20,2 +hydra-public-high,Develop,stage,20,2 +hydra-public-high,Enterprise,dev,40,3 +hydra-public-high,Enterprise,prod,320,10 +hydra-public-high,Enterprise,stage,40,3 +hydra-public-high,Growth,dev,40,3 +hydra-public-high,Growth,prod,160,7 +hydra-public-high,Growth,stage,40,3 +hydra-public-high,Production,dev,40,3 +hydra-public-high,Production,prod,80,4 +hydra-public-high,Production,stage,40,3 +hydra-public-low,Develop,dev,60,3 +hydra-public-low,Develop,prod,60,3 +hydra-public-low,Develop,stage,60,3 +hydra-public-low,Enterprise,dev,120,7 +hydra-public-low,Enterprise,prod,1500,55 +hydra-public-low,Enterprise,stage,120,7 +hydra-public-low,Growth,dev,120,7 +hydra-public-low,Growth,prod,720,30 +hydra-public-low,Growth,stage,120,7 +hydra-public-low,Production,dev,120,7 +hydra-public-low,Production,prod,250,10 +hydra-public-low,Production,stage,120,7 +hydra-public-medium,Develop,dev,40,3 +hydra-public-medium,Develop,prod,40,3 +hydra-public-medium,Develop,stage,40,3 +hydra-public-medium,Enterprise,dev,80,4 +hydra-public-medium,Enterprise,dev,80,4 +hydra-public-medium,Enterprise,prod,3000,100 +hydra-public-medium,Enterprise,prod,3500,120 +hydra-public-medium,Enterprise,stage,80,4 +hydra-public-medium,Enterprise,stage,80,4 +hydra-public-medium,Growth,dev,80,4 +hydra-public-medium,Growth,prod,1000,35 +hydra-public-medium,Growth,stage,80,4 +hydra-public-medium,Production,dev,80,4 +hydra-public-medium,Production,prod,320,10 +hydra-public-medium,Production,stage,80,4 +keto-admin-high,Develop,dev,60,3 +keto-admin-high,Develop,prod,60,3 +keto-admin-high,Develop,stage,60,3 +keto-admin-high,Enterprise,dev,120,7 +keto-admin-high,Enterprise,prod,1000,35 +keto-admin-high,Enterprise,stage,120,7 +keto-admin-high,Growth,dev,120,7 +keto-admin-high,Growth,prod,250,10 +keto-admin-high,Growth,stage,120,7 +keto-admin-high,Production,dev,120,7 +keto-admin-high,Production,prod,250,10 +keto-admin-high,Production,stage,120,7 +keto-admin-medium,Develop,dev,100,5 +keto-admin-medium,Develop,prod,100,5 +keto-admin-medium,Develop,stage,100,5 +keto-admin-medium,Enterprise,dev,200,10 +keto-admin-medium,Enterprise,prod,2000,70 +keto-admin-medium,Enterprise,stage,200,10 +keto-admin-medium,Growth,dev,200,10 +keto-admin-medium,Growth,prod,1000,35 +keto-admin-medium,Growth,stage,200,10 +keto-admin-medium,Production,dev,200,10 +keto-admin-medium,Production,prod,500,20 +keto-admin-medium,Production,stage,200,10 +keto-public-low,Develop,dev,120,7 +keto-public-low,Develop,prod,120,7 +keto-public-low,Develop,stage,120,7 +keto-public-low,Enterprise,dev,240,10 +keto-public-low,Enterprise,prod,18000,600 +keto-public-low,Enterprise,stage,240,10 +keto-public-low,Growth,dev,240,10 +keto-public-low,Growth,prod,9000,300 +keto-public-low,Growth,stage,240,10 +keto-public-low,Production,dev,240,10 +keto-public-low,Production,prod,1500,55 +keto-public-low,Production,stage,240,10 +kratos-admin-high,Develop,dev,100,5 +kratos-admin-high,Develop,prod,100,5 +kratos-admin-high,Develop,stage,100,5 +kratos-admin-high,Enterprise,dev,200,10 +kratos-admin-high,Enterprise,prod,2400,80 +kratos-admin-high,Enterprise,stage,200,10 +kratos-admin-high,Growth,dev,200,10 +kratos-admin-high,Growth,dev,200,10 +kratos-admin-high,Growth,prod,1200,45 +kratos-admin-high,Growth,prod,3500,120 +kratos-admin-high,Growth,stage,200,10 +kratos-admin-high,Growth,stage,200,10 +kratos-admin-high,Production,dev,200,10 +kratos-admin-high,Production,prod,400,15 +kratos-admin-high,Production,stage,200,10 +kratos-admin-low,Develop,dev,100,5 +kratos-admin-low,Develop,prod,100,5 +kratos-admin-low,Develop,stage,100,5 +kratos-admin-low,Enterprise,dev,200,10 +kratos-admin-low,Enterprise,dev,200,10 +kratos-admin-low,Enterprise,prod,2400,80 +kratos-admin-low,Enterprise,prod,6000,200 +kratos-admin-low,Enterprise,stage,200,10 +kratos-admin-low,Enterprise,stage,200,10 +kratos-admin-low,Growth,dev,200,10 +kratos-admin-low,Growth,prod,1200,45 +kratos-admin-low,Growth,stage,200,10 +kratos-admin-low,Production,dev,200,10 +kratos-admin-low,Production,prod,400,15 +kratos-admin-low,Production,stage,200,10 +kratos-admin-medium,Develop,dev,50,3 +kratos-admin-medium,Develop,prod,50,3 +kratos-admin-medium,Develop,stage,50,3 +kratos-admin-medium,Enterprise,dev,100,5 +kratos-admin-medium,Enterprise,prod,800,30 +kratos-admin-medium,Enterprise,stage,100,5 +kratos-admin-medium,Growth,dev,100,5 +kratos-admin-medium,Growth,dev,100,5 +kratos-admin-medium,Growth,prod,400,15 +kratos-admin-medium,Growth,prod,1000,35 +kratos-admin-medium,Growth,stage,100,5 +kratos-admin-medium,Growth,stage,100,5 +kratos-admin-medium,Production,dev,100,5 +kratos-admin-medium,Production,prod,200,10 +kratos-admin-medium,Production,stage,100,5 +kratos-public-high,Develop,dev,50,3 +kratos-public-high,Develop,prod,50,3 +kratos-public-high,Develop,stage,50,3 +kratos-public-high,Enterprise,dev,100,5 +kratos-public-high,Enterprise,prod,1200,45 +kratos-public-high,Enterprise,stage,100,5 +kratos-public-high,Growth,dev,100,5 +kratos-public-high,Growth,dev,100,5 +kratos-public-high,Growth,prod,600,25 +kratos-public-high,Growth,prod,1200,45 +kratos-public-high,Growth,stage,100,5 +kratos-public-high,Growth,stage,100,5 +kratos-public-high,Production,dev,100,5 +kratos-public-high,Production,prod,200,10 +kratos-public-high,Production,stage,100,5 +kratos-public-low,Develop,dev,200,10 +kratos-public-low,Develop,prod,200,10 +kratos-public-low,Develop,stage,200,10 +kratos-public-low,Enterprise,dev,400,15 +kratos-public-low,Enterprise,dev,400,15 +kratos-public-low,Enterprise,prod,21600,700 +kratos-public-low,Enterprise,prod,36000,1000 +kratos-public-low,Enterprise,stage,400,15 +kratos-public-low,Enterprise,stage,400,15 +kratos-public-low,Growth,dev,400,15 +kratos-public-low,Growth,dev,400,15 +kratos-public-low,Growth,prod,7200,240 +kratos-public-low,Growth,prod,21600,700 +kratos-public-low,Growth,stage,400,15 +kratos-public-low,Growth,stage,400,15 +kratos-public-low,Production,dev,400,15 +kratos-public-low,Production,prod,2400,80 +kratos-public-low,Production,stage,400,15 +kratos-public-medium,Develop,dev,100,5 +kratos-public-medium,Develop,prod,100,5 +kratos-public-medium,Develop,stage,100,5 +kratos-public-medium,Enterprise,dev,200,10 +kratos-public-medium,Enterprise,prod,1600,55 +kratos-public-medium,Enterprise,stage,200,10 +kratos-public-medium,Growth,dev,200,10 +kratos-public-medium,Growth,dev,200,10 +kratos-public-medium,Growth,prod,800,30 +kratos-public-medium,Growth,prod,4500,150 +kratos-public-medium,Growth,stage,200,10 +kratos-public-medium,Growth,stage,200,10 +kratos-public-medium,Production,dev,200,10 +kratos-public-medium,Production,prod,400,15 +kratos-public-medium,Production,stage,200,10 +polis-public-low,Develop,dev,15,2 +polis-public-low,Develop,prod,15,2 +polis-public-low,Develop,stage,15,2 +polis-public-low,Enterprise,dev,30,2 +polis-public-low,Enterprise,prod,250,10 +polis-public-low,Enterprise,stage,30,2 +polis-public-low,Growth,dev,30,2 +polis-public-low,Growth,prod,120,7 +polis-public-low,Growth,stage,30,2 +polis-public-low,Production,dev,30,2 +polis-public-low,Production,prod,60,3 +polis-public-low,Production,stage,30,2 +polis-public-medium,Develop,dev,60,3 +polis-public-medium,Develop,prod,60,3 +polis-public-medium,Develop,stage,60,3 +polis-public-medium,Enterprise,dev,120,7 +polis-public-medium,Enterprise,prod,1000,35 +polis-public-medium,Enterprise,stage,120,7 +polis-public-medium,Growth,dev,120,7 +polis-public-medium,Growth,prod,500,20 +polis-public-medium,Growth,stage,120,7 +polis-public-medium,Production,dev,120,7 +polis-public-medium,Production,prod,250,10 +polis-public-medium,Production,stage,120,7 diff --git a/src/lib/rate-limits/index.ts b/src/lib/rate-limits/index.ts new file mode 100644 index 0000000000..396f23ba1b --- /dev/null +++ b/src/lib/rate-limits/index.ts @@ -0,0 +1,14 @@ +// Copyright © 2022 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +export type { + EndpointRow, + Env, + GetThresholdsOptions, + RateLimitsProvider, + ThresholdRow, + Tier, +} from "./types" +export { ENV_FROM_CSV, TIER_FROM_CSV } from "./types" +export { getProvider, setProvider } from "./provider" +export { createCsvProvider } from "./csv-provider" diff --git a/src/lib/rate-limits/provider.ts b/src/lib/rate-limits/provider.ts new file mode 100644 index 0000000000..a285a31a2a --- /dev/null +++ b/src/lib/rate-limits/provider.ts @@ -0,0 +1,25 @@ +// Copyright © 2022 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +import type { RateLimitsProvider } from "./types" +import { createCsvProvider } from "./csv-provider" + +let defaultProvider: RateLimitsProvider | null = null + +/** + * Returns the active rate limits provider. Default is the CSV provider. + * When RATE_LIMITS_API_BASE (or equivalent) is set, can be switched to API provider later. + */ +export function getProvider(): RateLimitsProvider { + if (!defaultProvider) { + defaultProvider = createCsvProvider() + } + return defaultProvider +} + +/** + * For tests or when you want to inject a different provider. + */ +export function setProvider(provider: RateLimitsProvider): void { + defaultProvider = provider +} diff --git a/src/lib/rate-limits/types.ts b/src/lib/rate-limits/types.ts new file mode 100644 index 0000000000..28c1e37d42 --- /dev/null +++ b/src/lib/rate-limits/types.ts @@ -0,0 +1,69 @@ +// Copyright © 2022 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +/** + * Subscription tier (doc-friendly; CSV has "Develop" which we normalize to "Developer"). + */ +export type Tier = + | "Developer" + | "Production" + | "Growth" + | "Enterprise" + +/** + * Project environment (doc-friendly; CSV has dev/prod/stage which we normalize). + */ +export type Env = "Development" | "Staging" | "Production" + +/** + * One row from the bucket-to-endpoints CSV: method + path → bucket. + */ +export interface EndpointRow { + method: string + path: string + bucket: string +} + +/** + * One row from the bucket-to-threshold CSV: bucket + tier + env → rpm, rps. + * Tier and env are normalized to doc-friendly values. + */ +export interface ThresholdRow { + bucket: string + tier: Tier + env: Env + rpm: number + rps: number +} + +/** + * Options to filter getThresholds() results. + */ +export interface GetThresholdsOptions { + tier?: Tier + env?: Env + bucket?: string +} + +/** + * Provider interface: same shape for CSV or future API provider. + */ +export interface RateLimitsProvider { + getEndpointsByBucket(): Promise + getThresholds(options?: GetThresholdsOptions): Promise +} + +/** CSV tier value → doc-friendly Tier */ +export const TIER_FROM_CSV: Record = { + Develop: "Developer", + Production: "Production", + Growth: "Growth", + Enterprise: "Enterprise", +} + +/** CSV env value → doc-friendly Env */ +export const ENV_FROM_CSV: Record = { + dev: "Development", + prod: "Production", + stage: "Staging", +} diff --git a/src/plugins/docusaurus-rate-limits-data/index.ts b/src/plugins/docusaurus-rate-limits-data/index.ts new file mode 100644 index 0000000000..e7f96b04a4 --- /dev/null +++ b/src/plugins/docusaurus-rate-limits-data/index.ts @@ -0,0 +1,28 @@ +// Copyright © 2022 Ory Corp +// SPDX-License-Identifier: Apache-2.0 + +import * as fs from "fs" +import * as path from "path" +import type { PluginModule } from "@docusaurus/types" +import { createCsvProvider } from "../../lib/rate-limits/csv-provider" + +const plugin: PluginModule = async (context) => { + const siteDir = context.siteDir + const provider = createCsvProvider({ siteDir }) + const [endpoints, thresholds] = await Promise.all([ + provider.getEndpointsByBucket(), + provider.getThresholds(), + ]) + const staticDir = path.join(siteDir, "src", "static") + if (!fs.existsSync(staticDir)) { + fs.mkdirSync(staticDir, { recursive: true }) + } + const outPath = path.join(staticDir, "rate-limits.json") + fs.writeFileSync(outPath, JSON.stringify({ endpoints, thresholds }), "utf-8") + + return { + name: "docusaurus-rate-limits-data", + } +} + +export default plugin diff --git a/src/static/rate-limits.json b/src/static/rate-limits.json new file mode 100644 index 0000000000..b122294ec4 --- /dev/null +++ b/src/static/rate-limits.json @@ -0,0 +1 @@ +{"endpoints":[{"method":"GET","path":"/.well-known/jwks.json","bucket":"hydra-public-low"},{"method":"GET","path":"/.well-known/openid-configuration","bucket":"hydra-public-low"},{"method":"GET","path":"/.well-known/ory/webauthn.js","bucket":"hydra-public-low"},{"method":"GET","path":"/admin/clients","bucket":"hydra-admin-medium"},{"method":"POST","path":"/admin/clients","bucket":"hydra-admin-high"},{"method":"GET","path":"/admin/clients/{id}","bucket":"hydra-admin-low"},{"method":"DELETE","path":"/admin/clients/{id}","bucket":"hydra-admin-high"},{"method":"PATCH","path":"/admin/clients/{id}","bucket":"hydra-admin-high"},{"method":"PUT","path":"/admin/clients/{id}","bucket":"hydra-admin-high"},{"method":"HEAD","path":"/.well-known/openid-configuration","bucket":"hydra-public-low"},{"method":"PUT","path":"/admin/clients/{id}/lifespans","bucket":"hydra-admin-high"},{"method":"GET","path":"/admin/keys/{set}","bucket":"hydra-admin-medium"},{"method":"DELETE","path":"/admin/keys/{set}","bucket":"hydra-admin-high"},{"method":"POST","path":"/admin/keys/{set}","bucket":"hydra-admin-high"},{"method":"PUT","path":"/admin/keys/{set}","bucket":"hydra-admin-high"},{"method":"GET","path":"/admin/keys/{set}/{kid}","bucket":"hydra-admin-medium"},{"method":"DELETE","path":"/admin/keys/{set}/{kid}","bucket":"hydra-admin-high"},{"method":"PUT","path":"/admin/keys/{set}/{kid}","bucket":"hydra-admin-high"},{"method":"GET","path":"/admin/oauth2/auth/requests/consent","bucket":"hydra-admin-low"},{"method":"PUT","path":"/admin/oauth2/auth/requests/consent/accept","bucket":"hydra-admin-low"},{"method":"PUT","path":"/admin/oauth2/auth/requests/consent/reject","bucket":"hydra-admin-low"},{"method":"PUT","path":"/admin/oauth2/auth/requests/device/accept","bucket":"hydra-admin-low"},{"method":"GET","path":"/admin/oauth2/auth/requests/login","bucket":"hydra-admin-low"},{"method":"PUT","path":"/admin/oauth2/auth/requests/login/accept","bucket":"hydra-admin-low"},{"method":"PUT","path":"/admin/oauth2/auth/requests/login/reject","bucket":"hydra-admin-low"},{"method":"GET","path":"/admin/oauth2/auth/requests/logout","bucket":"hydra-admin-low"},{"method":"PUT","path":"/admin/oauth2/auth/requests/logout/accept","bucket":"hydra-admin-low"},{"method":"PUT","path":"/admin/oauth2/auth/requests/logout/reject","bucket":"hydra-admin-low"},{"method":"GET","path":"/admin/oauth2/auth/sessions/consent","bucket":"hydra-admin-low"},{"method":"DELETE","path":"/admin/oauth2/auth/sessions/consent","bucket":"hydra-admin-high"},{"method":"DELETE","path":"/admin/oauth2/auth/sessions/login","bucket":"hydra-admin-high"},{"method":"POST","path":"/admin/oauth2/introspect","bucket":"hydra-admin-low"},{"method":"DELETE","path":"/admin/oauth2/tokens","bucket":"hydra-admin-high"},{"method":"GET","path":"/admin/trust/grants/jwt-bearer/issuers","bucket":"hydra-admin-medium"},{"method":"POST","path":"/admin/trust/grants/jwt-bearer/issuers","bucket":"hydra-admin-high"},{"method":"GET","path":"/admin/trust/grants/jwt-bearer/issuers/{id}","bucket":"hydra-admin-medium"},{"method":"DELETE","path":"/admin/trust/grants/jwt-bearer/issuers/{id}","bucket":"hydra-admin-high"},{"method":"OPTIONS","path":"/admin/clients","bucket":"hydra-admin-low"},{"method":"OPTIONS","path":"/admin/clients/{id}","bucket":"hydra-admin-low"},{"method":"POST","path":"/credentials","bucket":"hydra-admin-medium"},{"method":"GET","path":"/oauth2/auth","bucket":"hydra-public-medium"},{"method":"HEAD","path":"/oauth2/auth","bucket":"hydra-public-low"},{"method":"POST","path":"/oauth2/device/auth","bucket":"hydra-public-low"},{"method":"GET","path":"/oauth2/device/verify","bucket":"hydra-admin-low"},{"method":"OPTIONS","path":"/oauth2/auth","bucket":"hydra-public-low"},{"method":"POST","path":"/oauth2/register","bucket":"hydra-public-high"},{"method":"GET","path":"/oauth2/register/{id}","bucket":"hydra-admin-low"},{"method":"DELETE","path":"/oauth2/register/{id}","bucket":"hydra-public-high"},{"method":"PUT","path":"/oauth2/register/{id}","bucket":"hydra-public-high"},{"method":"POST","path":"/oauth2/revoke","bucket":"hydra-public-medium"},{"method":"GET","path":"/oauth2/sessions/logout","bucket":"hydra-public-medium"},{"method":"POST","path":"/oauth2/auth","bucket":"hydra-public-medium"},{"method":"POST","path":"/oauth2/token","bucket":"hydra-public-medium"},{"method":"GET","path":"/oauth2/consent","bucket":"hydra-public-low"},{"method":"GET","path":"/oauth2/fallbacks/logout/callback","bucket":"hydra-public-low"},{"method":"POST","path":"/oauth2/sessions/logout","bucket":"hydra-public-medium"},{"method":"OPTIONS","path":"/oauth2/token","bucket":"hydra-public-low"},{"method":"GET","path":"/userinfo","bucket":"hydra-public-medium"},{"method":"DELETE","path":"/admin/relation-tuples","bucket":"keto-admin-high"},{"method":"PATCH","path":"/admin/relation-tuples","bucket":"keto-admin-high"},{"method":"PUT","path":"/admin/relation-tuples","bucket":"keto-admin-high"},{"method":"GET","path":"/namespaces","bucket":"keto-admin-high"},{"method":"POST","path":"/opl/syntax/check","bucket":"keto-admin-medium"},{"method":"POST","path":"/ory.keto.relation_tuples.v1alpha2.CheckService/BatchCheck","bucket":"keto-public-low"},{"method":"POST","path":"/ory.keto.relation_tuples.v1alpha2.CheckService/Check","bucket":"keto-public-low"},{"method":"POST","path":"/ory.keto.relation_tuples.v1alpha2.WriteService/TransactRelationTuples","bucket":"keto-admin-high"},{"method":"GET","path":"/relation-tuples","bucket":"keto-admin-medium"},{"method":"POST","path":"/relation-tuples/batch/check","bucket":"keto-public-low"},{"method":"GET","path":"/relation-tuples/check","bucket":"keto-public-low"},{"method":"POST","path":"/relation-tuples/check","bucket":"keto-public-low"},{"method":"GET","path":"/relation-tuples/check/openapi","bucket":"keto-public-low"},{"method":"POST","path":"/relation-tuples/check/openapi","bucket":"keto-public-low"},{"method":"GET","path":"/relation-tuples/expand","bucket":"keto-admin-medium"},{"method":"GET","path":"/admin/courier/messages","bucket":"kratos-admin-high"},{"method":"PATCH","path":"/admin/identities","bucket":"kratos-admin-high"},{"method":"POST","path":"/admin/identities","bucket":"kratos-admin-high"},{"method":"DELETE","path":"/admin/identities/{id}","bucket":"kratos-admin-high"},{"method":"PATCH","path":"/admin/identities/{id}","bucket":"kratos-admin-high"},{"method":"PUT","path":"/admin/identities/{id}","bucket":"kratos-admin-high"},{"method":"DELETE","path":"/admin/identities/{id}/credentials/{type}","bucket":"kratos-admin-high"},{"method":"DELETE","path":"/admin/identities/{id}/sessions","bucket":"kratos-admin-high"},{"method":"POST","path":"/admin/recovery/code","bucket":"kratos-admin-high"},{"method":"POST","path":"/admin/recovery/link","bucket":"kratos-admin-high"},{"method":"DELETE","path":"/admin/sessions/{id}","bucket":"kratos-admin-high"},{"method":"PATCH","path":"/admin/sessions/{id}/extend","bucket":"kratos-admin-high"},{"method":"POST","path":"/scim/{client}/v2/Groups","bucket":"kratos-admin-high"},{"method":"PUT","path":"/scim/{client}/v2/Groups/{id}","bucket":"kratos-admin-high"},{"method":"PATCH","path":"/scim/{client}/v2/Groups/{id}","bucket":"kratos-admin-high"},{"method":"DELETE","path":"/scim/{client}/v2/Groups/{id}","bucket":"kratos-admin-high"},{"method":"POST","path":"/scim/{client}/v2/Users","bucket":"kratos-admin-high"},{"method":"PUT","path":"/scim/{client}/v2/Users/{id}","bucket":"kratos-admin-high"},{"method":"PATCH","path":"/scim/{client}/v2/Users/{id}","bucket":"kratos-admin-high"},{"method":"DELETE","path":"/scim/{client}/v2/Users/{id}","bucket":"kratos-admin-high"},{"method":"GET","path":"/admin/identities/{id}","bucket":"kratos-admin-low"},{"method":"GET","path":"/admin/sessions/{id}","bucket":"kratos-admin-low"},{"method":"OPTIONS","path":"/admin/identities/{id}","bucket":"kratos-admin-low"},{"method":"GET","path":"/admin/courier/messages/{id}","bucket":"kratos-admin-medium"},{"method":"GET","path":"/admin/identities","bucket":"kratos-admin-medium"},{"method":"GET","path":"/admin/identities/{id}/sessions","bucket":"kratos-admin-medium"},{"method":"GET","path":"/admin/identities/by/external/{externalID}","bucket":"kratos-admin-medium"},{"method":"GET","path":"/admin/sessions","bucket":"kratos-admin-medium"},{"method":"GET","path":"/schemas","bucket":"kratos-admin-medium"},{"method":"GET","path":"/schemas/{id}","bucket":"kratos-admin-medium"},{"method":"GET","path":"/scim/{client}/v2/Groups","bucket":"kratos-admin-medium"},{"method":"GET","path":"/scim/{client}/v2/Groups/{id}","bucket":"kratos-admin-medium"},{"method":"GET","path":"/scim/{client}/v2/Schemas","bucket":"kratos-admin-medium"},{"method":"GET","path":"/scim/{client}/v2/Schemas/{id}","bucket":"kratos-admin-medium"},{"method":"GET","path":"/scim/{client}/v2/ServiceProviderConfig","bucket":"kratos-admin-medium"},{"method":"GET","path":"/scim/{client}/v2/Users","bucket":"kratos-admin-medium"},{"method":"GET","path":"/scim/{client}/v2/Users/{id}","bucket":"kratos-admin-medium"},{"method":"GET","path":"/self-service/errors","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/fed-cm/parameters","bucket":"kratos-public-low"},{"method":"POST","path":"/self-service/fed-cm/token","bucket":"kratos-public-high"},{"method":"POST","path":"/self-service/login","bucket":"kratos-public-high"},{"method":"GET","path":"/self-service/login/api","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/login/browser","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/login/flows","bucket":"kratos-public-low"},{"method":"HEAD","path":"/self-service/fed-cm/parameters","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/logout","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/fed-cm/token","bucket":"kratos-public-low"},{"method":"DELETE","path":"/self-service/logout/api","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/logout/browser","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/login","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/login","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/methods/oidc/callback/{provider_id}","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/methods/oidc/organizations/{organization_id}","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/methods/saml/callback/{provider_id}","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/methods/saml/organizations/{organization_id}","bucket":"kratos-public-medium"},{"method":"POST","path":"/self-service/recovery","bucket":"kratos-public-high"},{"method":"HEAD","path":"/self-service/login/browser","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/login/browser","bucket":"kratos-public-low"},{"method":"POST","path":"/self-service/login/browser","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/recovery/api","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/recovery/browser","bucket":"kratos-public-medium"},{"method":"OPTIONS","path":"/self-service/login/flows","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/recovery/flows","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/logout","bucket":"kratos-public-low"},{"method":"POST","path":"/self-service/registration","bucket":"kratos-public-high"},{"method":"OPTIONS","path":"/self-service/logout/browser","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/methods/oidc/callback","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/registration/api","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/registration/browser","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/registration/flows","bucket":"kratos-public-low"},{"method":"POST","path":"/self-service/settings","bucket":"kratos-public-high"},{"method":"HEAD","path":"/self-service/methods/oidc/callback/{provider_id}","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/recovery","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/settings/api","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/settings/browser","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/settings/flows","bucket":"kratos-public-low"},{"method":"POST","path":"/self-service/verification","bucket":"kratos-public-high"},{"method":"HEAD","path":"/self-service/recovery","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/recovery","bucket":"kratos-public-low"},{"method":"HEAD","path":"/self-service/recovery/browser","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/verification/api","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/verification/browser","bucket":"kratos-public-medium"},{"method":"OPTIONS","path":"/self-service/recovery/browser","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/verification/flows","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/recovery/flows","bucket":"kratos-public-low"},{"method":"GET","path":"/sessions","bucket":"kratos-public-medium"},{"method":"DELETE","path":"/sessions","bucket":"kratos-public-high"},{"method":"DELETE","path":"/sessions/{id}","bucket":"kratos-public-high"},{"method":"GET","path":"/sessions/token-exchange","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/registration","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/registration","bucket":"kratos-public-low"},{"method":"HEAD","path":"/self-service/registration/browser","bucket":"kratos-public-low"},{"method":"GET","path":"/sessions/whoami","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/registration/browser","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/settings","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/settings","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/verification","bucket":"kratos-public-low"},{"method":"HEAD","path":"/self-service/verification","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/verification","bucket":"kratos-public-low"},{"method":"HEAD","path":"/self-service/verification/browser","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/verification/flows","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/sessions","bucket":"kratos-public-low"},{"method":"GET","path":"/saml/.well-known/idp-metadata","bucket":"polis-public-low"},{"method":"GET","path":"/saml/.well-known/saml.cer","bucket":"polis-public-low"},{"method":"GET","path":"/saml/.well-known/sp-metadata","bucket":"polis-public-low"},{"method":"GET","path":"/saml/api/error","bucket":"polis-public-low"},{"method":"POST","path":"/saml/api/identity-federation/sso","bucket":"polis-public-medium"},{"method":"GET","path":"/saml/api/identity-federation/sso","bucket":"polis-public-medium"},{"method":"POST","path":"/saml/api/oauth/authorize","bucket":"polis-public-medium"},{"method":"GET","path":"/saml/api/oauth/authorize","bucket":"polis-public-medium"},{"method":"GET","path":"/saml/api/oauth/oidc","bucket":"polis-public-medium"},{"method":"POST","path":"/saml/api/oauth/saml","bucket":"polis-public-medium"}],"thresholds":[{"bucket":"hydra-admin-high","tier":"Developer","env":"Development","rpm":20,"rps":2},{"bucket":"hydra-admin-high","tier":"Developer","env":"Production","rpm":20,"rps":2},{"bucket":"hydra-admin-high","tier":"Developer","env":"Staging","rpm":20,"rps":2},{"bucket":"hydra-admin-high","tier":"Enterprise","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-admin-high","tier":"Enterprise","env":"Production","rpm":320,"rps":10},{"bucket":"hydra-admin-high","tier":"Enterprise","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-admin-high","tier":"Growth","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-admin-high","tier":"Growth","env":"Production","rpm":160,"rps":7},{"bucket":"hydra-admin-high","tier":"Growth","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-admin-high","tier":"Production","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-admin-high","tier":"Production","env":"Production","rpm":80,"rps":4},{"bucket":"hydra-admin-high","tier":"Production","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-admin-low","tier":"Developer","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-admin-low","tier":"Developer","env":"Production","rpm":40,"rps":3},{"bucket":"hydra-admin-low","tier":"Developer","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-admin-low","tier":"Enterprise","env":"Development","rpm":80,"rps":4},{"bucket":"hydra-admin-low","tier":"Enterprise","env":"Production","rpm":4800,"rps":160},{"bucket":"hydra-admin-low","tier":"Enterprise","env":"Staging","rpm":80,"rps":4},{"bucket":"hydra-admin-low","tier":"Growth","env":"Development","rpm":80,"rps":4},{"bucket":"hydra-admin-low","tier":"Growth","env":"Production","rpm":2400,"rps":80},{"bucket":"hydra-admin-low","tier":"Growth","env":"Staging","rpm":80,"rps":4},{"bucket":"hydra-admin-low","tier":"Production","env":"Development","rpm":80,"rps":4},{"bucket":"hydra-admin-low","tier":"Production","env":"Production","rpm":250,"rps":10},{"bucket":"hydra-admin-low","tier":"Production","env":"Staging","rpm":80,"rps":4},{"bucket":"hydra-admin-medium","tier":"Developer","env":"Development","rpm":20,"rps":2},{"bucket":"hydra-admin-medium","tier":"Developer","env":"Production","rpm":20,"rps":2},{"bucket":"hydra-admin-medium","tier":"Developer","env":"Staging","rpm":20,"rps":2},{"bucket":"hydra-admin-medium","tier":"Enterprise","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-admin-medium","tier":"Enterprise","env":"Production","rpm":320,"rps":10},{"bucket":"hydra-admin-medium","tier":"Enterprise","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-admin-medium","tier":"Growth","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-admin-medium","tier":"Growth","env":"Production","rpm":160,"rps":7},{"bucket":"hydra-admin-medium","tier":"Growth","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-admin-medium","tier":"Production","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-admin-medium","tier":"Production","env":"Production","rpm":80,"rps":4},{"bucket":"hydra-admin-medium","tier":"Production","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-public-high","tier":"Developer","env":"Development","rpm":20,"rps":2},{"bucket":"hydra-public-high","tier":"Developer","env":"Production","rpm":20,"rps":2},{"bucket":"hydra-public-high","tier":"Developer","env":"Staging","rpm":20,"rps":2},{"bucket":"hydra-public-high","tier":"Enterprise","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-public-high","tier":"Enterprise","env":"Production","rpm":320,"rps":10},{"bucket":"hydra-public-high","tier":"Enterprise","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-public-high","tier":"Growth","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-public-high","tier":"Growth","env":"Production","rpm":160,"rps":7},{"bucket":"hydra-public-high","tier":"Growth","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-public-high","tier":"Production","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-public-high","tier":"Production","env":"Production","rpm":80,"rps":4},{"bucket":"hydra-public-high","tier":"Production","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-public-low","tier":"Developer","env":"Development","rpm":60,"rps":3},{"bucket":"hydra-public-low","tier":"Developer","env":"Production","rpm":60,"rps":3},{"bucket":"hydra-public-low","tier":"Developer","env":"Staging","rpm":60,"rps":3},{"bucket":"hydra-public-low","tier":"Enterprise","env":"Development","rpm":120,"rps":7},{"bucket":"hydra-public-low","tier":"Enterprise","env":"Production","rpm":1500,"rps":55},{"bucket":"hydra-public-low","tier":"Enterprise","env":"Staging","rpm":120,"rps":7},{"bucket":"hydra-public-low","tier":"Growth","env":"Development","rpm":120,"rps":7},{"bucket":"hydra-public-low","tier":"Growth","env":"Production","rpm":720,"rps":30},{"bucket":"hydra-public-low","tier":"Growth","env":"Staging","rpm":120,"rps":7},{"bucket":"hydra-public-low","tier":"Production","env":"Development","rpm":120,"rps":7},{"bucket":"hydra-public-low","tier":"Production","env":"Production","rpm":250,"rps":10},{"bucket":"hydra-public-low","tier":"Production","env":"Staging","rpm":120,"rps":7},{"bucket":"hydra-public-medium","tier":"Developer","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-public-medium","tier":"Developer","env":"Production","rpm":40,"rps":3},{"bucket":"hydra-public-medium","tier":"Developer","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-public-medium","tier":"Enterprise","env":"Development","rpm":80,"rps":4},{"bucket":"hydra-public-medium","tier":"Enterprise","env":"Production","rpm":3000,"rps":100},{"bucket":"hydra-public-medium","tier":"Enterprise","env":"Staging","rpm":80,"rps":4},{"bucket":"hydra-public-medium","tier":"Growth","env":"Development","rpm":80,"rps":4},{"bucket":"hydra-public-medium","tier":"Growth","env":"Production","rpm":1000,"rps":35},{"bucket":"hydra-public-medium","tier":"Growth","env":"Staging","rpm":80,"rps":4},{"bucket":"hydra-public-medium","tier":"Production","env":"Development","rpm":80,"rps":4},{"bucket":"hydra-public-medium","tier":"Production","env":"Production","rpm":320,"rps":10},{"bucket":"hydra-public-medium","tier":"Production","env":"Staging","rpm":80,"rps":4},{"bucket":"keto-admin-high","tier":"Developer","env":"Development","rpm":60,"rps":3},{"bucket":"keto-admin-high","tier":"Developer","env":"Production","rpm":60,"rps":3},{"bucket":"keto-admin-high","tier":"Developer","env":"Staging","rpm":60,"rps":3},{"bucket":"keto-admin-high","tier":"Enterprise","env":"Development","rpm":120,"rps":7},{"bucket":"keto-admin-high","tier":"Enterprise","env":"Production","rpm":1000,"rps":35},{"bucket":"keto-admin-high","tier":"Enterprise","env":"Staging","rpm":120,"rps":7},{"bucket":"keto-admin-high","tier":"Growth","env":"Development","rpm":120,"rps":7},{"bucket":"keto-admin-high","tier":"Growth","env":"Production","rpm":250,"rps":10},{"bucket":"keto-admin-high","tier":"Growth","env":"Staging","rpm":120,"rps":7},{"bucket":"keto-admin-high","tier":"Production","env":"Development","rpm":120,"rps":7},{"bucket":"keto-admin-high","tier":"Production","env":"Production","rpm":250,"rps":10},{"bucket":"keto-admin-high","tier":"Production","env":"Staging","rpm":120,"rps":7},{"bucket":"keto-admin-medium","tier":"Developer","env":"Development","rpm":100,"rps":5},{"bucket":"keto-admin-medium","tier":"Developer","env":"Production","rpm":100,"rps":5},{"bucket":"keto-admin-medium","tier":"Developer","env":"Staging","rpm":100,"rps":5},{"bucket":"keto-admin-medium","tier":"Enterprise","env":"Development","rpm":200,"rps":10},{"bucket":"keto-admin-medium","tier":"Enterprise","env":"Production","rpm":2000,"rps":70},{"bucket":"keto-admin-medium","tier":"Enterprise","env":"Staging","rpm":200,"rps":10},{"bucket":"keto-admin-medium","tier":"Growth","env":"Development","rpm":200,"rps":10},{"bucket":"keto-admin-medium","tier":"Growth","env":"Production","rpm":1000,"rps":35},{"bucket":"keto-admin-medium","tier":"Growth","env":"Staging","rpm":200,"rps":10},{"bucket":"keto-admin-medium","tier":"Production","env":"Development","rpm":200,"rps":10},{"bucket":"keto-admin-medium","tier":"Production","env":"Production","rpm":500,"rps":20},{"bucket":"keto-admin-medium","tier":"Production","env":"Staging","rpm":200,"rps":10},{"bucket":"keto-public-low","tier":"Developer","env":"Development","rpm":120,"rps":7},{"bucket":"keto-public-low","tier":"Developer","env":"Production","rpm":120,"rps":7},{"bucket":"keto-public-low","tier":"Developer","env":"Staging","rpm":120,"rps":7},{"bucket":"keto-public-low","tier":"Enterprise","env":"Development","rpm":240,"rps":10},{"bucket":"keto-public-low","tier":"Enterprise","env":"Production","rpm":18000,"rps":600},{"bucket":"keto-public-low","tier":"Enterprise","env":"Staging","rpm":240,"rps":10},{"bucket":"keto-public-low","tier":"Growth","env":"Development","rpm":240,"rps":10},{"bucket":"keto-public-low","tier":"Growth","env":"Production","rpm":9000,"rps":300},{"bucket":"keto-public-low","tier":"Growth","env":"Staging","rpm":240,"rps":10},{"bucket":"keto-public-low","tier":"Production","env":"Development","rpm":240,"rps":10},{"bucket":"keto-public-low","tier":"Production","env":"Production","rpm":1500,"rps":55},{"bucket":"keto-public-low","tier":"Production","env":"Staging","rpm":240,"rps":10},{"bucket":"kratos-admin-high","tier":"Developer","env":"Development","rpm":100,"rps":5},{"bucket":"kratos-admin-high","tier":"Developer","env":"Production","rpm":100,"rps":5},{"bucket":"kratos-admin-high","tier":"Developer","env":"Staging","rpm":100,"rps":5},{"bucket":"kratos-admin-high","tier":"Enterprise","env":"Development","rpm":200,"rps":10},{"bucket":"kratos-admin-high","tier":"Enterprise","env":"Production","rpm":2400,"rps":80},{"bucket":"kratos-admin-high","tier":"Enterprise","env":"Staging","rpm":200,"rps":10},{"bucket":"kratos-admin-high","tier":"Growth","env":"Development","rpm":200,"rps":10},{"bucket":"kratos-admin-high","tier":"Growth","env":"Production","rpm":1200,"rps":45},{"bucket":"kratos-admin-high","tier":"Growth","env":"Staging","rpm":200,"rps":10},{"bucket":"kratos-admin-high","tier":"Production","env":"Development","rpm":200,"rps":10},{"bucket":"kratos-admin-high","tier":"Production","env":"Production","rpm":400,"rps":15},{"bucket":"kratos-admin-high","tier":"Production","env":"Staging","rpm":200,"rps":10},{"bucket":"kratos-admin-low","tier":"Developer","env":"Development","rpm":100,"rps":5},{"bucket":"kratos-admin-low","tier":"Developer","env":"Production","rpm":100,"rps":5},{"bucket":"kratos-admin-low","tier":"Developer","env":"Staging","rpm":100,"rps":5},{"bucket":"kratos-admin-low","tier":"Enterprise","env":"Development","rpm":200,"rps":10},{"bucket":"kratos-admin-low","tier":"Enterprise","env":"Production","rpm":2400,"rps":80},{"bucket":"kratos-admin-low","tier":"Enterprise","env":"Staging","rpm":200,"rps":10},{"bucket":"kratos-admin-low","tier":"Growth","env":"Development","rpm":200,"rps":10},{"bucket":"kratos-admin-low","tier":"Growth","env":"Production","rpm":1200,"rps":45},{"bucket":"kratos-admin-low","tier":"Growth","env":"Staging","rpm":200,"rps":10},{"bucket":"kratos-admin-low","tier":"Production","env":"Development","rpm":200,"rps":10},{"bucket":"kratos-admin-low","tier":"Production","env":"Production","rpm":400,"rps":15},{"bucket":"kratos-admin-low","tier":"Production","env":"Staging","rpm":200,"rps":10},{"bucket":"kratos-admin-medium","tier":"Developer","env":"Development","rpm":50,"rps":3},{"bucket":"kratos-admin-medium","tier":"Developer","env":"Production","rpm":50,"rps":3},{"bucket":"kratos-admin-medium","tier":"Developer","env":"Staging","rpm":50,"rps":3},{"bucket":"kratos-admin-medium","tier":"Enterprise","env":"Development","rpm":100,"rps":5},{"bucket":"kratos-admin-medium","tier":"Enterprise","env":"Production","rpm":800,"rps":30},{"bucket":"kratos-admin-medium","tier":"Enterprise","env":"Staging","rpm":100,"rps":5},{"bucket":"kratos-admin-medium","tier":"Growth","env":"Development","rpm":100,"rps":5},{"bucket":"kratos-admin-medium","tier":"Growth","env":"Production","rpm":400,"rps":15},{"bucket":"kratos-admin-medium","tier":"Growth","env":"Staging","rpm":100,"rps":5},{"bucket":"kratos-admin-medium","tier":"Production","env":"Development","rpm":100,"rps":5},{"bucket":"kratos-admin-medium","tier":"Production","env":"Production","rpm":200,"rps":10},{"bucket":"kratos-admin-medium","tier":"Production","env":"Staging","rpm":100,"rps":5},{"bucket":"kratos-public-high","tier":"Developer","env":"Development","rpm":50,"rps":3},{"bucket":"kratos-public-high","tier":"Developer","env":"Production","rpm":50,"rps":3},{"bucket":"kratos-public-high","tier":"Developer","env":"Staging","rpm":50,"rps":3},{"bucket":"kratos-public-high","tier":"Enterprise","env":"Development","rpm":100,"rps":5},{"bucket":"kratos-public-high","tier":"Enterprise","env":"Production","rpm":1200,"rps":45},{"bucket":"kratos-public-high","tier":"Enterprise","env":"Staging","rpm":100,"rps":5},{"bucket":"kratos-public-high","tier":"Growth","env":"Development","rpm":100,"rps":5},{"bucket":"kratos-public-high","tier":"Growth","env":"Production","rpm":600,"rps":25},{"bucket":"kratos-public-high","tier":"Growth","env":"Staging","rpm":100,"rps":5},{"bucket":"kratos-public-high","tier":"Production","env":"Development","rpm":100,"rps":5},{"bucket":"kratos-public-high","tier":"Production","env":"Production","rpm":200,"rps":10},{"bucket":"kratos-public-high","tier":"Production","env":"Staging","rpm":100,"rps":5},{"bucket":"kratos-public-low","tier":"Developer","env":"Development","rpm":200,"rps":10},{"bucket":"kratos-public-low","tier":"Developer","env":"Production","rpm":200,"rps":10},{"bucket":"kratos-public-low","tier":"Developer","env":"Staging","rpm":200,"rps":10},{"bucket":"kratos-public-low","tier":"Enterprise","env":"Development","rpm":400,"rps":15},{"bucket":"kratos-public-low","tier":"Enterprise","env":"Production","rpm":21600,"rps":700},{"bucket":"kratos-public-low","tier":"Enterprise","env":"Staging","rpm":400,"rps":15},{"bucket":"kratos-public-low","tier":"Growth","env":"Development","rpm":400,"rps":15},{"bucket":"kratos-public-low","tier":"Growth","env":"Production","rpm":7200,"rps":240},{"bucket":"kratos-public-low","tier":"Growth","env":"Staging","rpm":400,"rps":15},{"bucket":"kratos-public-low","tier":"Production","env":"Development","rpm":400,"rps":15},{"bucket":"kratos-public-low","tier":"Production","env":"Production","rpm":2400,"rps":80},{"bucket":"kratos-public-low","tier":"Production","env":"Staging","rpm":400,"rps":15},{"bucket":"kratos-public-medium","tier":"Developer","env":"Development","rpm":100,"rps":5},{"bucket":"kratos-public-medium","tier":"Developer","env":"Production","rpm":100,"rps":5},{"bucket":"kratos-public-medium","tier":"Developer","env":"Staging","rpm":100,"rps":5},{"bucket":"kratos-public-medium","tier":"Enterprise","env":"Development","rpm":200,"rps":10},{"bucket":"kratos-public-medium","tier":"Enterprise","env":"Production","rpm":1600,"rps":55},{"bucket":"kratos-public-medium","tier":"Enterprise","env":"Staging","rpm":200,"rps":10},{"bucket":"kratos-public-medium","tier":"Growth","env":"Development","rpm":200,"rps":10},{"bucket":"kratos-public-medium","tier":"Growth","env":"Production","rpm":800,"rps":30},{"bucket":"kratos-public-medium","tier":"Growth","env":"Staging","rpm":200,"rps":10},{"bucket":"kratos-public-medium","tier":"Production","env":"Development","rpm":200,"rps":10},{"bucket":"kratos-public-medium","tier":"Production","env":"Production","rpm":400,"rps":15},{"bucket":"kratos-public-medium","tier":"Production","env":"Staging","rpm":200,"rps":10},{"bucket":"polis-public-low","tier":"Developer","env":"Development","rpm":15,"rps":2},{"bucket":"polis-public-low","tier":"Developer","env":"Production","rpm":15,"rps":2},{"bucket":"polis-public-low","tier":"Developer","env":"Staging","rpm":15,"rps":2},{"bucket":"polis-public-low","tier":"Enterprise","env":"Development","rpm":30,"rps":2},{"bucket":"polis-public-low","tier":"Enterprise","env":"Production","rpm":250,"rps":10},{"bucket":"polis-public-low","tier":"Enterprise","env":"Staging","rpm":30,"rps":2},{"bucket":"polis-public-low","tier":"Growth","env":"Development","rpm":30,"rps":2},{"bucket":"polis-public-low","tier":"Growth","env":"Production","rpm":120,"rps":7},{"bucket":"polis-public-low","tier":"Growth","env":"Staging","rpm":30,"rps":2},{"bucket":"polis-public-low","tier":"Production","env":"Development","rpm":30,"rps":2},{"bucket":"polis-public-low","tier":"Production","env":"Production","rpm":60,"rps":3},{"bucket":"polis-public-low","tier":"Production","env":"Staging","rpm":30,"rps":2},{"bucket":"polis-public-medium","tier":"Developer","env":"Development","rpm":60,"rps":3},{"bucket":"polis-public-medium","tier":"Developer","env":"Production","rpm":60,"rps":3},{"bucket":"polis-public-medium","tier":"Developer","env":"Staging","rpm":60,"rps":3},{"bucket":"polis-public-medium","tier":"Enterprise","env":"Development","rpm":120,"rps":7},{"bucket":"polis-public-medium","tier":"Enterprise","env":"Production","rpm":1000,"rps":35},{"bucket":"polis-public-medium","tier":"Enterprise","env":"Staging","rpm":120,"rps":7},{"bucket":"polis-public-medium","tier":"Growth","env":"Development","rpm":120,"rps":7},{"bucket":"polis-public-medium","tier":"Growth","env":"Production","rpm":500,"rps":20},{"bucket":"polis-public-medium","tier":"Growth","env":"Staging","rpm":120,"rps":7},{"bucket":"polis-public-medium","tier":"Production","env":"Development","rpm":120,"rps":7},{"bucket":"polis-public-medium","tier":"Production","env":"Production","rpm":250,"rps":10},{"bucket":"polis-public-medium","tier":"Production","env":"Staging","rpm":120,"rps":7}]} \ No newline at end of file diff --git a/src/theme/MDXComponents.js b/src/theme/MDXComponents.js index 0b86d05a4d..80c50aa08f 100644 --- a/src/theme/MDXComponents.js +++ b/src/theme/MDXComponents.js @@ -4,12 +4,14 @@ import Tabs from "@theme/Tabs" import TabItem from "@theme/TabItem" import AjaxWarning from "./AjaxWarning" import ConsoleLink from "../components/ConsoleLink/console-link" +import RateLimitsTable from "../components/RateLimitsTable" export default { // Re-use the default mapping ...MDXComponents, AjaxWarning, ConsoleLink, + RateLimitsTable, Tabs, TabItem, } From 3aa2fc0172fca02bd320fccc38b140fff4a5653c Mon Sep 17 00:00:00 2001 From: unatasha8 Date: Wed, 4 Mar 2026 16:27:43 -0800 Subject: [PATCH 2/7] docs: update content around new rate limit tables --- docs/guides/rate-limits.mdx | 287 ++++++++++++++---------------------- 1 file changed, 114 insertions(+), 173 deletions(-) diff --git a/docs/guides/rate-limits.mdx b/docs/guides/rate-limits.mdx index 8cdb86deed..86703fc2ce 100644 --- a/docs/guides/rate-limits.mdx +++ b/docs/guides/rate-limits.mdx @@ -1,193 +1,102 @@ --- id: rate-limits -title: Understand Ory Network rate limiting +title: Understand Ory Network rate limits sidebar_label: Rate limits --- -This page provides a high-level overview of the rate limiting mechanisms employed by Ory to ensure system security and -availability. Rate limiting protects your applications against abuse and attacks, prevents service disruptions, and ensures fair -usage for all our customers. +:::info Rate limit changes +The way Ory calculates rate limits is changing. Customers who joined before March 1, 2026, keep their existing rate limits. New customers are subject to the updated calculation. +::: -## Types of rate limits +Ory uses rate limiting to protect your applications against abuse, attacks, and service disruptions, and to maintain fair resource +allocation and network stability. -Ory implements two main rate limit types: +## Types of rate limits -1. Project rate limits: Based on your subscription plan and environment (Production, Staging, or Development). These control the - overall request volume your projects can make to Ory's APIs. -2. Endpoint-based rate limits: Additional security controls that protect specific endpoints against attacks like brute-force, - credential stuffing, and concurrent request abuse, regardless of your project limits. +Ory uses two types of rate limits: -## Project rate limits in workspaces +- [Project rate limits](#project-rate-limits): Control the overall request volume your projects can make to Ory APIs, based on your subscription tier and +project environment. +- [Endpoint-based rate limits](#endpoint-based-rate-limits): Control traffic to individual endpoints to protect against volumetric attacks, brute-force +attempts, and concurrent request abuse—regardless of your project rate limits. -With the introduction of workspaces in Ory Network, rate limits are now applied to projects based on their assigned environment -and the workspace's subscription plan. This approach ensures fair resource allocation and maintains the stability of the Ory -Network across different usage scenarios. +Project rate limits use a bucket system to group endpoints and apply thresholds. Understanding how buckets work will help you interpret +the project rate limit table below. -### How project rate limits work in workspaces +## Project rate limits -Rate limits for each project are determined by two main factors: +Each project has a set of rate limit buckets. A bucket is a named group of API endpoints that share the same rate limit thresholds. When a request comes in, +Ory resolves which bucket the endpoint belongs to and applies the threshold for that bucket. -1. Workspace subscription: Your subscription plan (Developer, Production, Growth, or Enterprise) sets the baseline for your rate - limits. -2. Project environment: Within each workspace, projects can be assigned to Production, Staging, or Development environments, each - with specific rate limit configurations. +Bucket thresholds are determined by two factors: -For a detailed explanation of workspaces and environments, see our [Workspaces and environments guide](/docs/guides/workspaces). +- **Subscription tier:** The project's subscription tier (Developer, Production, Growth, or Enterprise). +- **Project environment:** The project's environment (Production, Staging, or Development). -### Rate limit structure +For a detailed explanation of tiers and environments, see our [Workspaces and environments guide](/docs/guides/workspaces). -Each rate limit policy includes two limits: +### Bucket naming + Buckets follow a `{service}-{access}-{cost}` naming pattern. For example: -1. Burst limit: Maximum requests per second (rps), allowing for short traffic spikes. -2. Sustained limit: Maximum requests per minute (rpm), ensuring consistent performance over time. +- `kratos-public-low` — lightweight public endpoints like `GET /sessions/whoami` +- `kratos-admin-high` — expensive admin operations like `POST /admin/identities` +- `hydra-public-medium` — moderate-cost endpoints like `POST /oauth2/token` -### Determine your project's rate limits - -To identify the rate limits that apply to your project: - -1. Check your workspace subscription plan (Developer, Production, Growth, or Enterprise). -2. Identify the environment (Production, Staging, or Development) assigned to your project. -3. Use the interactive table below to filter by tier and environment, or search by API path to find which bucket and limits apply to a given endpoint. +:::info +A bucket counter is shared across all endpoints in the same bucket. For example, `POST /admin/relation-tuples` and  +`DELETE /admin/relation-tuples` both belong to `keto-admin-high`, so every call to either endpoint counts against the +same limit. Plan your request volumes accordingly. +::: -### Interactive rate limit tables +### Rate limit structure - +You will see two rate limits for each bucket: -### Rate limit tables by subscription plan (reference) - -#### Developer plan rate limits - -| Environment | Path / Bucket | Burst (rps) | Sustained (rpm) | -| :---------- | :-------------------------------- | ----------: | --------------: | -| Development | `/sessions/whoami` | 10 | 300 | -| | `/admin/oauth2/introspect` | 10 | 300 | -| | `/relation-tuples/check` | 10 | 300 | -| | `GET /admin/identities` | 1 | 10 | -| | `POST /admin/identities` | 1 | 10 | -| | `PATCH /admin/identities` | 1 | 10 | -| | `POST /admin/recovery/*` | 1 | 10 | -| | `POST /self-service/registration` | 1 | 10 | -| | `POST /self-service/recovery` | 1 | 10 | -| | `POST /self-service/settings` | 1 | 10 | -| | `POST /self-service/verification` | 1 | 10 | -| | `/scim/**` | 1 | 10 | -| | `*` | 5 | 150 | +1. Burst limit: Maximum requests per second (rps), allowing for short traffic spikes. +2. Sustained limit: Maximum requests per minute (rpm), ensuring consistent performance over time. -:::note +### Monitor rate limit headers -For Developer plans, all environments (Production, Staging, Development) use the same rate limits. +Ory Network includes rate limit information in API response headers for project rate-limits. Use these headers to avoid +exceeding the applicable rate limit. Your client must handle these responses to maintain service quality. -::: +| Header | Description | +| --- | --- | +| `x-ratelimit-limit` | The rate limit ceiling(s) for the current request, including burst and sustained limits | +| `x-ratelimit-remaining` | Number of requests remaining in the current window | +| `x-ratelimit-reset` | Number of seconds until the rate limit window resets | -#### Production plan rate limits - -| Environment | Path / Bucket | Burst (rps) | Sustained (rpm) | -| :-------------------- | :-------------------------------- | ----------: | --------------: | -| Production | `/sessions/whoami` | 80 | 1800 | -| | `/admin/oauth2/introspect` | 80 | 1800 | -| | `/relation-tuples/check` | 80 | 1800 | -| | `GET /admin/identities` | 10 | 300 | -| | `POST /admin/recovery/*` | 10 | 30 | -| | `/scim/**` | 10 | 300 | -| | `*` | 40 | 900 | -| Development / Staging | `/sessions/whoami` | 10 | 300 | -| | `/admin/oauth2/introspect` | 10 | 300 | -| | `/relation-tuples/check` | 10 | 300 | -| | `GET /admin/identities` | 1 | 10 | -| | `POST /admin/identities` | 1 | 10 | -| | `PATCH /admin/identities` | 1 | 10 | -| | `POST /admin/recovery/*` | 1 | 10 | -| | `POST /self-service/registration` | 1 | 10 | -| | `POST /self-service/recovery` | 1 | 10 | -| | `POST /self-service/settings` | 1 | 10 | -| | `POST /self-service/verification` | 1 | 10 | -| | `/scim/**` | 1 | 10 | -| | `*` | 5 | 150 | +Example header values: -:::note +```shell +x-ratelimit-limit: 10, 10;w=1, 300;w=60 +x-ratelimit-remaining: 8 +x-ratelimit-reset: 1 +``` -Production plan rate limits also apply to the Legacy `Essential` plan. +The `x-ratelimit-limit` header follows the [IETF RateLimit header fields draft](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/), +where `w=1` indicates a 1-second window and `w=60` indicates a 60-second window. Use these headers to throttle requests +proactively and reduce the likelihood of hitting 429 errors. -::: +See [How to handle 429 responses](#how-to-handle-429-responses) for an example of how to deal with potential 429 responses. -#### Growth plan rate limits - -| Environment | Path / Bucket | Burst (rps) | Sustained (rpm) | -| :-------------------- | :-------------------------------- | ----------: | --------------: | -| Production | `/sessions/whoami` | 800 | 18000 | -| | `/admin/oauth2/introspect` | 800 | 18000 | -| | `/relation-tuples/check` | 800 | 18000 | -| | `GET /admin/identities` | 20 | 600 | -| | `POST /admin/recovery/*` | 10 | 300 | -| | `/scim/**` | 10 | 300 | -| | `*` | 400 | 9000 | -| Development / Staging | `/sessions/whoami` | 10 | 300 | -| | `/admin/oauth2/introspect` | 10 | 300 | -| | `/relation-tuples/check` | 10 | 300 | -| | `GET /admin/identities` | 1 | 10 | -| | `POST /admin/identities` | 1 | 10 | -| | `PATCH /admin/identities` | 1 | 10 | -| | `POST /admin/recovery/*` | 1 | 10 | -| | `POST /self-service/registration` | 1 | 10 | -| | `POST /self-service/recovery` | 1 | 10 | -| | `POST /self-service/settings` | 1 | 10 | -| | `POST /self-service/verification` | 1 | 10 | -| | `/scim/**` | 1 | 10 | -| | `*` | 5 | 150 | +## Calculate the rate limits that apply to your project -:::note +In the **Project rate limit table** below: -Growth plan rate limits also apply to the legacy `Scale` plan. +1. Select your subscription tier from the **Tier** dropdown. Options are Developer, Production, Growth, or Enterprise. +2. Select your project environment from the **Environment** dropdown. Options are Production, Staging, or Development. +3. To search by API path, enter the API path into the **Search API path** box. The endpoint appears highlighted. Look to see +which bucket it belongs to for its rate limit. -::: +### Project rate limit table -#### Enterprise plan rate limits - -The Enterprise plan has the same default rate limits as the Growth plan. If your use case requires higher limits, -[get in touch with us to discuss your requirements](https://ory.com/contact). - -| Environment | Path / Bucket | Burst (rps) | Sustained (rpm) | -| :-------------------- | :-------------------------------- | ----------: | --------------: | -| Production | `/sessions/whoami` | 1200 | 36000 | -| | `/admin/oauth2/introspect` | 1200 | 36000 | -| | `/relation-tuples/check` | 1200 | 36000 | -| | `GET /admin/identities` | 60 | 1200 | -| | `POST /admin/recovery/*` | 20 | 600 | -| | `/scim/**` | 20 | 600 | -| | `*` | 800 | 18000 | -| Development / Staging | `/sessions/whoami` | 10 | 300 | -| | `/admin/oauth2/introspect` | 10 | 300 | -| | `/relation-tuples/check` | 10 | 300 | -| | `GET /admin/identities` | 1 | 10 | -| | `POST /admin/identities` | 1 | 10 | -| | `PATCH /admin/identities` | 1 | 10 | -| | `POST /admin/recovery/*` | 1 | 10 | -| | `POST /self-service/registration` | 1 | 10 | -| | `POST /self-service/recovery` | 1 | 10 | -| | `POST /self-service/settings` | 1 | 10 | -| | `POST /self-service/verification` | 1 | 10 | -| | `/scim/**` | 1 | 10 | -| | `*` | 5 | 150 | + ## Endpoint-based rate limits -Endpoint-based rate limits are controls applied to individual API endpoints within your Ory projects. Unlike project rate limits, -which govern overall project request volumes, endpoint-based rate limits focus on safeguarding specific functionalities against -abuse. - -:::note - -Endpoint-based rate limits operate independently from project rate limits in workspaces. While project rate limits control overall -request volumes based on your subscription and environment, endpoint-based rate limits provide additional security for specific -endpoints regardless of your project rate limit values. - -::: - -### Purpose of endpoint-based rate limits - -Endpoint-based rate limits protect individual endpoints against common attack vectors like brute-force and credential stuffing. -These attacks typically involve numerous attempts to guess credentials or exploit vulnerabilities, often from a limited set of IP -addresses or JA4 fingerprints. +Endpoint-based rate limits apply to individual API endpoints regardless of your project rate limits. They protect specific endpoints +against brute-force and credential stuffing attacks, which typically originate from a limited set of IP addresses or JA4 fingerprints. Benefits: @@ -201,7 +110,7 @@ Ory implements two layers of endpoint-based protection: #### Volumetric rate limits -Analyzes incoming request patterns based on: +Volumetric rate limits analyze incoming request patterns based on: - Source identification: IP addresses and JA3/JA4 fingerprints - Request frequency: Detects volumetric attacks and system overwhelm attempts @@ -211,20 +120,13 @@ Analyzes incoming request patterns based on: #### Inflight rate limits Inflight rate limits protect critical endpoints from concurrent request attacks. By preventing multiple requests to the same -resource at once, it eliminates race conditions, ensures data consistency, and lets critical operations complete safely. - -:::note - -These limits mainly protect against write requests to the same resource happening in parallel — usually caused by implementation -issues. - -::: +resource at once, they eliminate race conditions, ensure data consistency, and let critical operations complete safely. ### Protected endpoints -The following endpoints are protected by different types of rate limiting: +The following endpoints are protected by volumetric or inflight rate limits. -| Type | Endpoint | HTTP Methods | Ratelimit Key | Action | +| Type | Endpoint | HTTP Methods | Ratelimit Key | Action: enforced vs report-only | | :--------- | :------------------------------------------ | :----------------------- | :----------------------------------------------- | :------------------------------------- | | Volumetric | | | | To be added later | | Inflight | `/admin/identities` | `POST`, `PATCH` | `{project_id} + {full_path}` | Blocks concurrent requests (enforced) | @@ -236,16 +138,55 @@ The following endpoints are protected by different types of rate limiting: | Inflight | `/self-service/recovery` | `POST` | `{project_id} + {path} + "/" + {email\|flow_id}` | Logs concurrent requests (report-only) | :::note +Enforced-endpoints return HTTP 429 when the rate limit is exceeded. Report-only-endpoints currently only log rate limit violations; +they don't block requests. GET, OPTIONS, and HEAD requests are exempt from rate limiting. +::: -Report-only endpoints are observed over a period of time before enforcement is enabled. They currently log rate limit violations -for monitoring purposes but don't block requests, while enforced endpoints return HTTP 429 when rate limits are exceeded. GET, -OPTIONS, and HEAD requests are exempt from rate limiting. +### Configuration and rule management -::: +The endpoint-based rate limit rules are set and managed by Ory. These rules aren't directly configurable by customers. + +## How to handle 429 responses + +When your client receives a `429 Too Many Requests` response, you've exceeded the applicable rate limit. Your client must handle these +responses to maintain service quality. + +Your implementation must: + +- **Detect 429 responses**: Monitor for HTTP 429 status codes on all API calls. +- **Implement exponential backoff**: When receiving a 429, pause and retry with increasing delays (for example: 1s, 2s, 4s, 8s). +- **Respect rate limit headers**: Check `x-ratelimit-remaining` and `x-ratelimit-reset`, when available, to throttle requests proactively. +- **Avoid retry storms**: Don't retry failed requests in a tight loop. + +### Exponential backoff strategy + +Implement an exponential backoff strategy to proactively avoid hitting rate limits. + +```jsx +async function callApiWithBackoff(request, maxRetries = 5) { + for (let attempt = 0; attempt < maxRetries; attempt++) { + const response = await fetch(request); + if (response.status === 429) { + const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s, 8s, 16s + await new Promise(resolve => setTimeout(resolve, delay)); + continue; + } + return response; + } + throw new Error('Max retries exceeded'); +} +``` + +See [Monitor rate limit headers](#monitor-rate-limit-headers) for information about how to monitor rate limit headers and throttle requests proactively. + + +Clients that repeatedly exceed rate limits without proper backoff may have their API access temporarily blocked. For high-volume use +cases that exceed your plan's limits, open a support ticket via the [Ory Console](https://console.ory.sh/support) or email +[support@ory.sh](mailto:support@ory.sh). -### Configuration and management +## Load and performance testing -#### Rule management +Load testing, stress testing, and performance testing against Ory Network require prior written approval. Unauthorized load testing may +be detected as abusive traffic and result in temporary blocking of your project or IP addresses. -The endpoint-based rate limit rules are set and managed by Ory. These rules aren't directly configurable by Enterprise and Growth -customers yet. +For eligibility, request procedures, and requirements, see the [Load Testing Policy](https://www.ory.sh/legal/load-testing-policy). From 02a61ee58220242f922c72b4a2b98fc933aecc4c Mon Sep 17 00:00:00 2001 From: unatasha8 Date: Wed, 4 Mar 2026 16:46:36 -0800 Subject: [PATCH 3/7] docs: make format updates --- docs/guides/rate-limits.mdx | 110 +- src/components/RateLimitsTable/index.tsx | 8 +- src/lib/rate-limits/csv-provider.ts | 31 +- src/lib/rate-limits/types.ts | 6 +- src/static/rate-limits.json | 2332 +++++++++++++++++++++- 5 files changed, 2418 insertions(+), 69 deletions(-) diff --git a/docs/guides/rate-limits.mdx b/docs/guides/rate-limits.mdx index 86703fc2ce..7d975410d9 100644 --- a/docs/guides/rate-limits.mdx +++ b/docs/guides/rate-limits.mdx @@ -4,49 +4,47 @@ title: Understand Ory Network rate limits sidebar_label: Rate limits --- -:::info Rate limit changes -The way Ory calculates rate limits is changing. Customers who joined before March 1, 2026, keep their existing rate limits. New customers are subject to the updated calculation. -::: +:::info Rate limit changes The way Ory calculates rate limits is changing. Customers who joined before March 1, 2026, keep their +existing rate limits. New customers are subject to the updated calculation. ::: -Ory uses rate limiting to protect your applications against abuse, attacks, and service disruptions, and to maintain fair resource +Ory uses rate limiting to protect your applications against abuse, attacks, and service disruptions, and to maintain fair resource allocation and network stability. ## Types of rate limits Ory uses two types of rate limits: -- [Project rate limits](#project-rate-limits): Control the overall request volume your projects can make to Ory APIs, based on your subscription tier and -project environment. -- [Endpoint-based rate limits](#endpoint-based-rate-limits): Control traffic to individual endpoints to protect against volumetric attacks, brute-force -attempts, and concurrent request abuse—regardless of your project rate limits. +- [Project rate limits](#project-rate-limits): Control the overall request volume your projects can make to Ory APIs, based on + your subscription tier and project environment. +- [Endpoint-based rate limits](#endpoint-based-rate-limits): Control traffic to individual endpoints to protect against volumetric + attacks, brute-force attempts, and concurrent request abuse—regardless of your project rate limits. -Project rate limits use a bucket system to group endpoints and apply thresholds. Understanding how buckets work will help you interpret -the project rate limit table below. +Project rate limits use a bucket system to group endpoints and apply thresholds. Understanding how buckets work will help you +interpret the project rate limit table below. ## Project rate limits -Each project has a set of rate limit buckets. A bucket is a named group of API endpoints that share the same rate limit thresholds. When a request comes in, -Ory resolves which bucket the endpoint belongs to and applies the threshold for that bucket. +Each project has a set of rate limit buckets. A bucket is a named group of API endpoints that share the same rate limit +thresholds. When a request comes in, Ory resolves which bucket the endpoint belongs to and applies the threshold for that bucket. Bucket thresholds are determined by two factors: - **Subscription tier:** The project's subscription tier (Developer, Production, Growth, or Enterprise). -- **Project environment:** The project's environment (Production, Staging, or Development). +- **Project environment:** The project's environment (Production, Staging, or Development). For a detailed explanation of tiers and environments, see our [Workspaces and environments guide](/docs/guides/workspaces). ### Bucket naming - Buckets follow a `{service}-{access}-{cost}` naming pattern. For example: + +Buckets follow a `{service}-{access}-{cost}` naming pattern. For example: - `kratos-public-low` — lightweight public endpoints like `GET /sessions/whoami` - `kratos-admin-high` — expensive admin operations like `POST /admin/identities` - `hydra-public-medium` — moderate-cost endpoints like `POST /oauth2/token` -:::info -A bucket counter is shared across all endpoints in the same bucket. For example, `POST /admin/relation-tuples` and  -`DELETE /admin/relation-tuples` both belong to `keto-admin-high`, so every call to either endpoint counts against the -same limit. Plan your request volumes accordingly. -::: +:::info A bucket counter is shared across all endpoints in the same bucket. For example, `POST /admin/relation-tuples` and  +`DELETE /admin/relation-tuples` both belong to `keto-admin-high`, so every call to either endpoint counts against the same limit. +Plan your request volumes accordingly. ::: ### Rate limit structure @@ -57,14 +55,14 @@ You will see two rate limits for each bucket: ### Monitor rate limit headers -Ory Network includes rate limit information in API response headers for project rate-limits. Use these headers to avoid -exceeding the applicable rate limit. Your client must handle these responses to maintain service quality. +Ory Network includes rate limit information in API response headers for project rate-limits. Use these headers to avoid exceeding +the applicable rate limit. Your client must handle these responses to maintain service quality. -| Header | Description | -| --- | --- | -| `x-ratelimit-limit` | The rate limit ceiling(s) for the current request, including burst and sustained limits | -| `x-ratelimit-remaining` | Number of requests remaining in the current window | -| `x-ratelimit-reset` | Number of seconds until the rate limit window resets | +| Header | Description | +| ----------------------- | --------------------------------------------------------------------------------------- | +| `x-ratelimit-limit` | The rate limit ceiling(s) for the current request, including burst and sustained limits | +| `x-ratelimit-remaining` | Number of requests remaining in the current window | +| `x-ratelimit-reset` | Number of seconds until the rate limit window resets | Example header values: @@ -74,20 +72,21 @@ x-ratelimit-remaining: 8 x-ratelimit-reset: 1 ``` -The `x-ratelimit-limit` header follows the [IETF RateLimit header fields draft](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/), -where `w=1` indicates a 1-second window and `w=60` indicates a 60-second window. Use these headers to throttle requests -proactively and reduce the likelihood of hitting 429 errors. +The `x-ratelimit-limit` header follows the +[IETF RateLimit header fields draft](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/), where `w=1` +indicates a 1-second window and `w=60` indicates a 60-second window. Use these headers to throttle requests proactively and reduce +the likelihood of hitting 429 errors. See [How to handle 429 responses](#how-to-handle-429-responses) for an example of how to deal with potential 429 responses. ## Calculate the rate limits that apply to your project -In the **Project rate limit table** below: +In the **Project rate limit table** below: 1. Select your subscription tier from the **Tier** dropdown. Options are Developer, Production, Growth, or Enterprise. 2. Select your project environment from the **Environment** dropdown. Options are Production, Staging, or Development. -3. To search by API path, enter the API path into the **Search API path** box. The endpoint appears highlighted. Look to see -which bucket it belongs to for its rate limit. +3. To search by API path, enter the API path into the **Search API path** box. The endpoint appears highlighted. Look to see which + bucket it belongs to for its rate limit. ### Project rate limit table @@ -95,8 +94,9 @@ which bucket it belongs to for its rate limit. ## Endpoint-based rate limits -Endpoint-based rate limits apply to individual API endpoints regardless of your project rate limits. They protect specific endpoints -against brute-force and credential stuffing attacks, which typically originate from a limited set of IP addresses or JA4 fingerprints. +Endpoint-based rate limits apply to individual API endpoints regardless of your project rate limits. They protect specific +endpoints against brute-force and credential stuffing attacks, which typically originate from a limited set of IP addresses or JA4 +fingerprints. Benefits: @@ -126,7 +126,7 @@ resource at once, they eliminate race conditions, ensure data consistency, and l The following endpoints are protected by volumetric or inflight rate limits. -| Type | Endpoint | HTTP Methods | Ratelimit Key | Action: enforced vs report-only | +| Type | Endpoint | HTTP Methods | Ratelimit Key | Action: enforced vs report-only | | :--------- | :------------------------------------------ | :----------------------- | :----------------------------------------------- | :------------------------------------- | | Volumetric | | | | To be added later | | Inflight | `/admin/identities` | `POST`, `PATCH` | `{project_id} + {full_path}` | Blocks concurrent requests (enforced) | @@ -137,10 +137,8 @@ The following endpoints are protected by volumetric or inflight rate limits. | Inflight | `/admin/sessions/{id}/extend` | `PATCH` | `{project_id} + {full_path}` | Logs concurrent requests (report-only) | | Inflight | `/self-service/recovery` | `POST` | `{project_id} + {path} + "/" + {email\|flow_id}` | Logs concurrent requests (report-only) | -:::note -Enforced-endpoints return HTTP 429 when the rate limit is exceeded. Report-only-endpoints currently only log rate limit violations; -they don't block requests. GET, OPTIONS, and HEAD requests are exempt from rate limiting. -::: +:::note Enforced-endpoints return HTTP 429 when the rate limit is exceeded. Report-only-endpoints currently only log rate limit +violations; they don't block requests. GET, OPTIONS, and HEAD requests are exempt from rate limiting. ::: ### Configuration and rule management @@ -148,14 +146,15 @@ The endpoint-based rate limit rules are set and managed by Ory. These rules aren ## How to handle 429 responses -When your client receives a `429 Too Many Requests` response, you've exceeded the applicable rate limit. Your client must handle these -responses to maintain service quality. +When your client receives a `429 Too Many Requests` response, you've exceeded the applicable rate limit. Your client must handle +these responses to maintain service quality. Your implementation must: - **Detect 429 responses**: Monitor for HTTP 429 status codes on all API calls. - **Implement exponential backoff**: When receiving a 429, pause and retry with increasing delays (for example: 1s, 2s, 4s, 8s). -- **Respect rate limit headers**: Check `x-ratelimit-remaining` and `x-ratelimit-reset`, when available, to throttle requests proactively. +- **Respect rate limit headers**: Check `x-ratelimit-remaining` and `x-ratelimit-reset`, when available, to throttle requests + proactively. - **Avoid retry storms**: Don't retry failed requests in a tight loop. ### Exponential backoff strategy @@ -165,28 +164,29 @@ Implement an exponential backoff strategy to proactively avoid hitting rate limi ```jsx async function callApiWithBackoff(request, maxRetries = 5) { for (let attempt = 0; attempt < maxRetries; attempt++) { - const response = await fetch(request); + const response = await fetch(request) if (response.status === 429) { - const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s, 8s, 16s - await new Promise(resolve => setTimeout(resolve, delay)); - continue; + const delay = Math.pow(2, attempt) * 1000 // 1s, 2s, 4s, 8s, 16s + await new Promise((resolve) => setTimeout(resolve, delay)) + continue } - return response; + return response } - throw new Error('Max retries exceeded'); + throw new Error("Max retries exceeded") } ``` -See [Monitor rate limit headers](#monitor-rate-limit-headers) for information about how to monitor rate limit headers and throttle requests proactively. - +See [Monitor rate limit headers](#monitor-rate-limit-headers) for information about how to monitor rate limit headers and throttle +requests proactively. -Clients that repeatedly exceed rate limits without proper backoff may have their API access temporarily blocked. For high-volume use -cases that exceed your plan's limits, open a support ticket via the [Ory Console](https://console.ory.sh/support) or email +Clients that repeatedly exceed rate limits without proper backoff may have their API access temporarily blocked. For high-volume +use cases that exceed your plan's limits, open a support ticket via the [Ory Console](https://console.ory.sh/support) or email [support@ory.sh](mailto:support@ory.sh). ## Load and performance testing -Load testing, stress testing, and performance testing against Ory Network require prior written approval. Unauthorized load testing may -be detected as abusive traffic and result in temporary blocking of your project or IP addresses. +Load testing, stress testing, and performance testing against Ory Network require prior written approval. Unauthorized load +testing may be detected as abusive traffic and result in temporary blocking of your project or IP addresses. -For eligibility, request procedures, and requirements, see the [Load Testing Policy](https://www.ory.sh/legal/load-testing-policy). +For eligibility, request procedures, and requirements, see the +[Load Testing Policy](https://www.ory.sh/legal/load-testing-policy). diff --git a/src/components/RateLimitsTable/index.tsx b/src/components/RateLimitsTable/index.tsx index fdeba1d645..9f16e37ef2 100644 --- a/src/components/RateLimitsTable/index.tsx +++ b/src/components/RateLimitsTable/index.tsx @@ -54,7 +54,10 @@ export default function RateLimitsTable({ const [pathSearchDebounced, setPathSearchDebounced] = useState("") useEffect(() => { - const t = setTimeout(() => setPathSearchDebounced(pathSearch), SEARCH_DEBOUNCE_MS) + const t = setTimeout( + () => setPathSearchDebounced(pathSearch), + SEARCH_DEBOUNCE_MS, + ) return () => clearTimeout(t) }, [pathSearch]) @@ -256,7 +259,8 @@ export default function RateLimitsTable({ {searchQuery && displayedThresholds.length === 0 && (

- No buckets match the search "{pathSearchDebounced.trim()}". + No buckets match the search "{pathSearchDebounced.trim()} + ".

)} diff --git a/src/lib/rate-limits/csv-provider.ts b/src/lib/rate-limits/csv-provider.ts index 261f6fbce1..5d951cf64f 100644 --- a/src/lib/rate-limits/csv-provider.ts +++ b/src/lib/rate-limits/csv-provider.ts @@ -3,7 +3,14 @@ import * as fs from "fs" import * as path from "path" -import type { EndpointRow, Env, GetThresholdsOptions, RateLimitsProvider, ThresholdRow, Tier } from "./types" +import type { + EndpointRow, + Env, + GetThresholdsOptions, + RateLimitsProvider, + ThresholdRow, + Tier, +} from "./types" import { ENV_FROM_CSV, TIER_FROM_CSV } from "./types" const ENDPOINTS_CSV = "bucket-to-endpoints-20260204-1941.csv" @@ -43,7 +50,9 @@ export interface CsvProviderOptions { siteDir?: string } -export function createCsvProvider(options?: CsvProviderOptions): RateLimitsProvider { +export function createCsvProvider( + options?: CsvProviderOptions, +): RateLimitsProvider { const dataDir = getDataDir(options?.siteDir) const endpointsPath = path.join(dataDir, ENDPOINTS_CSV) const thresholdsPath = path.join(dataDir, THRESHOLDS_CSV) @@ -53,7 +62,12 @@ export function createCsvProvider(options?: CsvProviderOptions): RateLimitsProvi const raw = fs.readFileSync(endpointsPath, "utf-8") const rows = parseCsv(raw) const [header, ...dataRows] = rows - if (!header || header[0] !== "Method" || header[1] !== "Path" || header[2] !== "Bucket") { + if ( + !header || + header[0] !== "Method" || + header[1] !== "Path" || + header[2] !== "Bucket" + ) { throw new Error(`Unexpected endpoints CSV header: ${header?.join(",")}`) } return dataRows @@ -61,7 +75,9 @@ export function createCsvProvider(options?: CsvProviderOptions): RateLimitsProvi .map((r) => ({ method: r[0], path: r[1], bucket: r[2] })) }, - async getThresholds(options?: GetThresholdsOptions): Promise { + async getThresholds( + options?: GetThresholdsOptions, + ): Promise { const raw = fs.readFileSync(thresholdsPath, "utf-8") const rows = parseCsv(raw) const [header, ...dataRows] = rows @@ -73,7 +89,9 @@ export function createCsvProvider(options?: CsvProviderOptions): RateLimitsProvi header[3] !== "rpm" || header[4] !== "rps" ) { - throw new Error(`Unexpected thresholds CSV header: ${header?.join(",")}`) + throw new Error( + `Unexpected thresholds CSV header: ${header?.join(",")}`, + ) } let result: ThresholdRow[] = dataRows .filter((r) => r.length >= 5 && r[0] && r[1] && r[2]) @@ -91,7 +109,8 @@ export function createCsvProvider(options?: CsvProviderOptions): RateLimitsProvi result = dedupeThresholds(result) if (options?.tier) result = result.filter((r) => r.tier === options.tier) if (options?.env) result = result.filter((r) => r.env === options.env) - if (options?.bucket) result = result.filter((r) => r.bucket === options.bucket) + if (options?.bucket) + result = result.filter((r) => r.bucket === options.bucket) return result }, } diff --git a/src/lib/rate-limits/types.ts b/src/lib/rate-limits/types.ts index 28c1e37d42..55e2626821 100644 --- a/src/lib/rate-limits/types.ts +++ b/src/lib/rate-limits/types.ts @@ -4,11 +4,7 @@ /** * Subscription tier (doc-friendly; CSV has "Develop" which we normalize to "Developer"). */ -export type Tier = - | "Developer" - | "Production" - | "Growth" - | "Enterprise" +export type Tier = "Developer" | "Production" | "Growth" | "Enterprise" /** * Project environment (doc-friendly; CSV has dev/prod/stage which we normalize). diff --git a/src/static/rate-limits.json b/src/static/rate-limits.json index b122294ec4..e1f6d31b20 100644 --- a/src/static/rate-limits.json +++ b/src/static/rate-limits.json @@ -1 +1,2331 @@ -{"endpoints":[{"method":"GET","path":"/.well-known/jwks.json","bucket":"hydra-public-low"},{"method":"GET","path":"/.well-known/openid-configuration","bucket":"hydra-public-low"},{"method":"GET","path":"/.well-known/ory/webauthn.js","bucket":"hydra-public-low"},{"method":"GET","path":"/admin/clients","bucket":"hydra-admin-medium"},{"method":"POST","path":"/admin/clients","bucket":"hydra-admin-high"},{"method":"GET","path":"/admin/clients/{id}","bucket":"hydra-admin-low"},{"method":"DELETE","path":"/admin/clients/{id}","bucket":"hydra-admin-high"},{"method":"PATCH","path":"/admin/clients/{id}","bucket":"hydra-admin-high"},{"method":"PUT","path":"/admin/clients/{id}","bucket":"hydra-admin-high"},{"method":"HEAD","path":"/.well-known/openid-configuration","bucket":"hydra-public-low"},{"method":"PUT","path":"/admin/clients/{id}/lifespans","bucket":"hydra-admin-high"},{"method":"GET","path":"/admin/keys/{set}","bucket":"hydra-admin-medium"},{"method":"DELETE","path":"/admin/keys/{set}","bucket":"hydra-admin-high"},{"method":"POST","path":"/admin/keys/{set}","bucket":"hydra-admin-high"},{"method":"PUT","path":"/admin/keys/{set}","bucket":"hydra-admin-high"},{"method":"GET","path":"/admin/keys/{set}/{kid}","bucket":"hydra-admin-medium"},{"method":"DELETE","path":"/admin/keys/{set}/{kid}","bucket":"hydra-admin-high"},{"method":"PUT","path":"/admin/keys/{set}/{kid}","bucket":"hydra-admin-high"},{"method":"GET","path":"/admin/oauth2/auth/requests/consent","bucket":"hydra-admin-low"},{"method":"PUT","path":"/admin/oauth2/auth/requests/consent/accept","bucket":"hydra-admin-low"},{"method":"PUT","path":"/admin/oauth2/auth/requests/consent/reject","bucket":"hydra-admin-low"},{"method":"PUT","path":"/admin/oauth2/auth/requests/device/accept","bucket":"hydra-admin-low"},{"method":"GET","path":"/admin/oauth2/auth/requests/login","bucket":"hydra-admin-low"},{"method":"PUT","path":"/admin/oauth2/auth/requests/login/accept","bucket":"hydra-admin-low"},{"method":"PUT","path":"/admin/oauth2/auth/requests/login/reject","bucket":"hydra-admin-low"},{"method":"GET","path":"/admin/oauth2/auth/requests/logout","bucket":"hydra-admin-low"},{"method":"PUT","path":"/admin/oauth2/auth/requests/logout/accept","bucket":"hydra-admin-low"},{"method":"PUT","path":"/admin/oauth2/auth/requests/logout/reject","bucket":"hydra-admin-low"},{"method":"GET","path":"/admin/oauth2/auth/sessions/consent","bucket":"hydra-admin-low"},{"method":"DELETE","path":"/admin/oauth2/auth/sessions/consent","bucket":"hydra-admin-high"},{"method":"DELETE","path":"/admin/oauth2/auth/sessions/login","bucket":"hydra-admin-high"},{"method":"POST","path":"/admin/oauth2/introspect","bucket":"hydra-admin-low"},{"method":"DELETE","path":"/admin/oauth2/tokens","bucket":"hydra-admin-high"},{"method":"GET","path":"/admin/trust/grants/jwt-bearer/issuers","bucket":"hydra-admin-medium"},{"method":"POST","path":"/admin/trust/grants/jwt-bearer/issuers","bucket":"hydra-admin-high"},{"method":"GET","path":"/admin/trust/grants/jwt-bearer/issuers/{id}","bucket":"hydra-admin-medium"},{"method":"DELETE","path":"/admin/trust/grants/jwt-bearer/issuers/{id}","bucket":"hydra-admin-high"},{"method":"OPTIONS","path":"/admin/clients","bucket":"hydra-admin-low"},{"method":"OPTIONS","path":"/admin/clients/{id}","bucket":"hydra-admin-low"},{"method":"POST","path":"/credentials","bucket":"hydra-admin-medium"},{"method":"GET","path":"/oauth2/auth","bucket":"hydra-public-medium"},{"method":"HEAD","path":"/oauth2/auth","bucket":"hydra-public-low"},{"method":"POST","path":"/oauth2/device/auth","bucket":"hydra-public-low"},{"method":"GET","path":"/oauth2/device/verify","bucket":"hydra-admin-low"},{"method":"OPTIONS","path":"/oauth2/auth","bucket":"hydra-public-low"},{"method":"POST","path":"/oauth2/register","bucket":"hydra-public-high"},{"method":"GET","path":"/oauth2/register/{id}","bucket":"hydra-admin-low"},{"method":"DELETE","path":"/oauth2/register/{id}","bucket":"hydra-public-high"},{"method":"PUT","path":"/oauth2/register/{id}","bucket":"hydra-public-high"},{"method":"POST","path":"/oauth2/revoke","bucket":"hydra-public-medium"},{"method":"GET","path":"/oauth2/sessions/logout","bucket":"hydra-public-medium"},{"method":"POST","path":"/oauth2/auth","bucket":"hydra-public-medium"},{"method":"POST","path":"/oauth2/token","bucket":"hydra-public-medium"},{"method":"GET","path":"/oauth2/consent","bucket":"hydra-public-low"},{"method":"GET","path":"/oauth2/fallbacks/logout/callback","bucket":"hydra-public-low"},{"method":"POST","path":"/oauth2/sessions/logout","bucket":"hydra-public-medium"},{"method":"OPTIONS","path":"/oauth2/token","bucket":"hydra-public-low"},{"method":"GET","path":"/userinfo","bucket":"hydra-public-medium"},{"method":"DELETE","path":"/admin/relation-tuples","bucket":"keto-admin-high"},{"method":"PATCH","path":"/admin/relation-tuples","bucket":"keto-admin-high"},{"method":"PUT","path":"/admin/relation-tuples","bucket":"keto-admin-high"},{"method":"GET","path":"/namespaces","bucket":"keto-admin-high"},{"method":"POST","path":"/opl/syntax/check","bucket":"keto-admin-medium"},{"method":"POST","path":"/ory.keto.relation_tuples.v1alpha2.CheckService/BatchCheck","bucket":"keto-public-low"},{"method":"POST","path":"/ory.keto.relation_tuples.v1alpha2.CheckService/Check","bucket":"keto-public-low"},{"method":"POST","path":"/ory.keto.relation_tuples.v1alpha2.WriteService/TransactRelationTuples","bucket":"keto-admin-high"},{"method":"GET","path":"/relation-tuples","bucket":"keto-admin-medium"},{"method":"POST","path":"/relation-tuples/batch/check","bucket":"keto-public-low"},{"method":"GET","path":"/relation-tuples/check","bucket":"keto-public-low"},{"method":"POST","path":"/relation-tuples/check","bucket":"keto-public-low"},{"method":"GET","path":"/relation-tuples/check/openapi","bucket":"keto-public-low"},{"method":"POST","path":"/relation-tuples/check/openapi","bucket":"keto-public-low"},{"method":"GET","path":"/relation-tuples/expand","bucket":"keto-admin-medium"},{"method":"GET","path":"/admin/courier/messages","bucket":"kratos-admin-high"},{"method":"PATCH","path":"/admin/identities","bucket":"kratos-admin-high"},{"method":"POST","path":"/admin/identities","bucket":"kratos-admin-high"},{"method":"DELETE","path":"/admin/identities/{id}","bucket":"kratos-admin-high"},{"method":"PATCH","path":"/admin/identities/{id}","bucket":"kratos-admin-high"},{"method":"PUT","path":"/admin/identities/{id}","bucket":"kratos-admin-high"},{"method":"DELETE","path":"/admin/identities/{id}/credentials/{type}","bucket":"kratos-admin-high"},{"method":"DELETE","path":"/admin/identities/{id}/sessions","bucket":"kratos-admin-high"},{"method":"POST","path":"/admin/recovery/code","bucket":"kratos-admin-high"},{"method":"POST","path":"/admin/recovery/link","bucket":"kratos-admin-high"},{"method":"DELETE","path":"/admin/sessions/{id}","bucket":"kratos-admin-high"},{"method":"PATCH","path":"/admin/sessions/{id}/extend","bucket":"kratos-admin-high"},{"method":"POST","path":"/scim/{client}/v2/Groups","bucket":"kratos-admin-high"},{"method":"PUT","path":"/scim/{client}/v2/Groups/{id}","bucket":"kratos-admin-high"},{"method":"PATCH","path":"/scim/{client}/v2/Groups/{id}","bucket":"kratos-admin-high"},{"method":"DELETE","path":"/scim/{client}/v2/Groups/{id}","bucket":"kratos-admin-high"},{"method":"POST","path":"/scim/{client}/v2/Users","bucket":"kratos-admin-high"},{"method":"PUT","path":"/scim/{client}/v2/Users/{id}","bucket":"kratos-admin-high"},{"method":"PATCH","path":"/scim/{client}/v2/Users/{id}","bucket":"kratos-admin-high"},{"method":"DELETE","path":"/scim/{client}/v2/Users/{id}","bucket":"kratos-admin-high"},{"method":"GET","path":"/admin/identities/{id}","bucket":"kratos-admin-low"},{"method":"GET","path":"/admin/sessions/{id}","bucket":"kratos-admin-low"},{"method":"OPTIONS","path":"/admin/identities/{id}","bucket":"kratos-admin-low"},{"method":"GET","path":"/admin/courier/messages/{id}","bucket":"kratos-admin-medium"},{"method":"GET","path":"/admin/identities","bucket":"kratos-admin-medium"},{"method":"GET","path":"/admin/identities/{id}/sessions","bucket":"kratos-admin-medium"},{"method":"GET","path":"/admin/identities/by/external/{externalID}","bucket":"kratos-admin-medium"},{"method":"GET","path":"/admin/sessions","bucket":"kratos-admin-medium"},{"method":"GET","path":"/schemas","bucket":"kratos-admin-medium"},{"method":"GET","path":"/schemas/{id}","bucket":"kratos-admin-medium"},{"method":"GET","path":"/scim/{client}/v2/Groups","bucket":"kratos-admin-medium"},{"method":"GET","path":"/scim/{client}/v2/Groups/{id}","bucket":"kratos-admin-medium"},{"method":"GET","path":"/scim/{client}/v2/Schemas","bucket":"kratos-admin-medium"},{"method":"GET","path":"/scim/{client}/v2/Schemas/{id}","bucket":"kratos-admin-medium"},{"method":"GET","path":"/scim/{client}/v2/ServiceProviderConfig","bucket":"kratos-admin-medium"},{"method":"GET","path":"/scim/{client}/v2/Users","bucket":"kratos-admin-medium"},{"method":"GET","path":"/scim/{client}/v2/Users/{id}","bucket":"kratos-admin-medium"},{"method":"GET","path":"/self-service/errors","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/fed-cm/parameters","bucket":"kratos-public-low"},{"method":"POST","path":"/self-service/fed-cm/token","bucket":"kratos-public-high"},{"method":"POST","path":"/self-service/login","bucket":"kratos-public-high"},{"method":"GET","path":"/self-service/login/api","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/login/browser","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/login/flows","bucket":"kratos-public-low"},{"method":"HEAD","path":"/self-service/fed-cm/parameters","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/logout","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/fed-cm/token","bucket":"kratos-public-low"},{"method":"DELETE","path":"/self-service/logout/api","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/logout/browser","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/login","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/login","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/methods/oidc/callback/{provider_id}","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/methods/oidc/organizations/{organization_id}","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/methods/saml/callback/{provider_id}","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/methods/saml/organizations/{organization_id}","bucket":"kratos-public-medium"},{"method":"POST","path":"/self-service/recovery","bucket":"kratos-public-high"},{"method":"HEAD","path":"/self-service/login/browser","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/login/browser","bucket":"kratos-public-low"},{"method":"POST","path":"/self-service/login/browser","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/recovery/api","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/recovery/browser","bucket":"kratos-public-medium"},{"method":"OPTIONS","path":"/self-service/login/flows","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/recovery/flows","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/logout","bucket":"kratos-public-low"},{"method":"POST","path":"/self-service/registration","bucket":"kratos-public-high"},{"method":"OPTIONS","path":"/self-service/logout/browser","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/methods/oidc/callback","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/registration/api","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/registration/browser","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/registration/flows","bucket":"kratos-public-low"},{"method":"POST","path":"/self-service/settings","bucket":"kratos-public-high"},{"method":"HEAD","path":"/self-service/methods/oidc/callback/{provider_id}","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/recovery","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/settings/api","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/settings/browser","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/settings/flows","bucket":"kratos-public-low"},{"method":"POST","path":"/self-service/verification","bucket":"kratos-public-high"},{"method":"HEAD","path":"/self-service/recovery","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/recovery","bucket":"kratos-public-low"},{"method":"HEAD","path":"/self-service/recovery/browser","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/verification/api","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/verification/browser","bucket":"kratos-public-medium"},{"method":"OPTIONS","path":"/self-service/recovery/browser","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/verification/flows","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/recovery/flows","bucket":"kratos-public-low"},{"method":"GET","path":"/sessions","bucket":"kratos-public-medium"},{"method":"DELETE","path":"/sessions","bucket":"kratos-public-high"},{"method":"DELETE","path":"/sessions/{id}","bucket":"kratos-public-high"},{"method":"GET","path":"/sessions/token-exchange","bucket":"kratos-public-medium"},{"method":"GET","path":"/self-service/registration","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/registration","bucket":"kratos-public-low"},{"method":"HEAD","path":"/self-service/registration/browser","bucket":"kratos-public-low"},{"method":"GET","path":"/sessions/whoami","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/registration/browser","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/settings","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/settings","bucket":"kratos-public-low"},{"method":"GET","path":"/self-service/verification","bucket":"kratos-public-low"},{"method":"HEAD","path":"/self-service/verification","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/verification","bucket":"kratos-public-low"},{"method":"HEAD","path":"/self-service/verification/browser","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/self-service/verification/flows","bucket":"kratos-public-low"},{"method":"OPTIONS","path":"/sessions","bucket":"kratos-public-low"},{"method":"GET","path":"/saml/.well-known/idp-metadata","bucket":"polis-public-low"},{"method":"GET","path":"/saml/.well-known/saml.cer","bucket":"polis-public-low"},{"method":"GET","path":"/saml/.well-known/sp-metadata","bucket":"polis-public-low"},{"method":"GET","path":"/saml/api/error","bucket":"polis-public-low"},{"method":"POST","path":"/saml/api/identity-federation/sso","bucket":"polis-public-medium"},{"method":"GET","path":"/saml/api/identity-federation/sso","bucket":"polis-public-medium"},{"method":"POST","path":"/saml/api/oauth/authorize","bucket":"polis-public-medium"},{"method":"GET","path":"/saml/api/oauth/authorize","bucket":"polis-public-medium"},{"method":"GET","path":"/saml/api/oauth/oidc","bucket":"polis-public-medium"},{"method":"POST","path":"/saml/api/oauth/saml","bucket":"polis-public-medium"}],"thresholds":[{"bucket":"hydra-admin-high","tier":"Developer","env":"Development","rpm":20,"rps":2},{"bucket":"hydra-admin-high","tier":"Developer","env":"Production","rpm":20,"rps":2},{"bucket":"hydra-admin-high","tier":"Developer","env":"Staging","rpm":20,"rps":2},{"bucket":"hydra-admin-high","tier":"Enterprise","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-admin-high","tier":"Enterprise","env":"Production","rpm":320,"rps":10},{"bucket":"hydra-admin-high","tier":"Enterprise","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-admin-high","tier":"Growth","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-admin-high","tier":"Growth","env":"Production","rpm":160,"rps":7},{"bucket":"hydra-admin-high","tier":"Growth","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-admin-high","tier":"Production","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-admin-high","tier":"Production","env":"Production","rpm":80,"rps":4},{"bucket":"hydra-admin-high","tier":"Production","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-admin-low","tier":"Developer","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-admin-low","tier":"Developer","env":"Production","rpm":40,"rps":3},{"bucket":"hydra-admin-low","tier":"Developer","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-admin-low","tier":"Enterprise","env":"Development","rpm":80,"rps":4},{"bucket":"hydra-admin-low","tier":"Enterprise","env":"Production","rpm":4800,"rps":160},{"bucket":"hydra-admin-low","tier":"Enterprise","env":"Staging","rpm":80,"rps":4},{"bucket":"hydra-admin-low","tier":"Growth","env":"Development","rpm":80,"rps":4},{"bucket":"hydra-admin-low","tier":"Growth","env":"Production","rpm":2400,"rps":80},{"bucket":"hydra-admin-low","tier":"Growth","env":"Staging","rpm":80,"rps":4},{"bucket":"hydra-admin-low","tier":"Production","env":"Development","rpm":80,"rps":4},{"bucket":"hydra-admin-low","tier":"Production","env":"Production","rpm":250,"rps":10},{"bucket":"hydra-admin-low","tier":"Production","env":"Staging","rpm":80,"rps":4},{"bucket":"hydra-admin-medium","tier":"Developer","env":"Development","rpm":20,"rps":2},{"bucket":"hydra-admin-medium","tier":"Developer","env":"Production","rpm":20,"rps":2},{"bucket":"hydra-admin-medium","tier":"Developer","env":"Staging","rpm":20,"rps":2},{"bucket":"hydra-admin-medium","tier":"Enterprise","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-admin-medium","tier":"Enterprise","env":"Production","rpm":320,"rps":10},{"bucket":"hydra-admin-medium","tier":"Enterprise","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-admin-medium","tier":"Growth","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-admin-medium","tier":"Growth","env":"Production","rpm":160,"rps":7},{"bucket":"hydra-admin-medium","tier":"Growth","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-admin-medium","tier":"Production","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-admin-medium","tier":"Production","env":"Production","rpm":80,"rps":4},{"bucket":"hydra-admin-medium","tier":"Production","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-public-high","tier":"Developer","env":"Development","rpm":20,"rps":2},{"bucket":"hydra-public-high","tier":"Developer","env":"Production","rpm":20,"rps":2},{"bucket":"hydra-public-high","tier":"Developer","env":"Staging","rpm":20,"rps":2},{"bucket":"hydra-public-high","tier":"Enterprise","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-public-high","tier":"Enterprise","env":"Production","rpm":320,"rps":10},{"bucket":"hydra-public-high","tier":"Enterprise","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-public-high","tier":"Growth","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-public-high","tier":"Growth","env":"Production","rpm":160,"rps":7},{"bucket":"hydra-public-high","tier":"Growth","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-public-high","tier":"Production","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-public-high","tier":"Production","env":"Production","rpm":80,"rps":4},{"bucket":"hydra-public-high","tier":"Production","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-public-low","tier":"Developer","env":"Development","rpm":60,"rps":3},{"bucket":"hydra-public-low","tier":"Developer","env":"Production","rpm":60,"rps":3},{"bucket":"hydra-public-low","tier":"Developer","env":"Staging","rpm":60,"rps":3},{"bucket":"hydra-public-low","tier":"Enterprise","env":"Development","rpm":120,"rps":7},{"bucket":"hydra-public-low","tier":"Enterprise","env":"Production","rpm":1500,"rps":55},{"bucket":"hydra-public-low","tier":"Enterprise","env":"Staging","rpm":120,"rps":7},{"bucket":"hydra-public-low","tier":"Growth","env":"Development","rpm":120,"rps":7},{"bucket":"hydra-public-low","tier":"Growth","env":"Production","rpm":720,"rps":30},{"bucket":"hydra-public-low","tier":"Growth","env":"Staging","rpm":120,"rps":7},{"bucket":"hydra-public-low","tier":"Production","env":"Development","rpm":120,"rps":7},{"bucket":"hydra-public-low","tier":"Production","env":"Production","rpm":250,"rps":10},{"bucket":"hydra-public-low","tier":"Production","env":"Staging","rpm":120,"rps":7},{"bucket":"hydra-public-medium","tier":"Developer","env":"Development","rpm":40,"rps":3},{"bucket":"hydra-public-medium","tier":"Developer","env":"Production","rpm":40,"rps":3},{"bucket":"hydra-public-medium","tier":"Developer","env":"Staging","rpm":40,"rps":3},{"bucket":"hydra-public-medium","tier":"Enterprise","env":"Development","rpm":80,"rps":4},{"bucket":"hydra-public-medium","tier":"Enterprise","env":"Production","rpm":3000,"rps":100},{"bucket":"hydra-public-medium","tier":"Enterprise","env":"Staging","rpm":80,"rps":4},{"bucket":"hydra-public-medium","tier":"Growth","env":"Development","rpm":80,"rps":4},{"bucket":"hydra-public-medium","tier":"Growth","env":"Production","rpm":1000,"rps":35},{"bucket":"hydra-public-medium","tier":"Growth","env":"Staging","rpm":80,"rps":4},{"bucket":"hydra-public-medium","tier":"Production","env":"Development","rpm":80,"rps":4},{"bucket":"hydra-public-medium","tier":"Production","env":"Production","rpm":320,"rps":10},{"bucket":"hydra-public-medium","tier":"Production","env":"Staging","rpm":80,"rps":4},{"bucket":"keto-admin-high","tier":"Developer","env":"Development","rpm":60,"rps":3},{"bucket":"keto-admin-high","tier":"Developer","env":"Production","rpm":60,"rps":3},{"bucket":"keto-admin-high","tier":"Developer","env":"Staging","rpm":60,"rps":3},{"bucket":"keto-admin-high","tier":"Enterprise","env":"Development","rpm":120,"rps":7},{"bucket":"keto-admin-high","tier":"Enterprise","env":"Production","rpm":1000,"rps":35},{"bucket":"keto-admin-high","tier":"Enterprise","env":"Staging","rpm":120,"rps":7},{"bucket":"keto-admin-high","tier":"Growth","env":"Development","rpm":120,"rps":7},{"bucket":"keto-admin-high","tier":"Growth","env":"Production","rpm":250,"rps":10},{"bucket":"keto-admin-high","tier":"Growth","env":"Staging","rpm":120,"rps":7},{"bucket":"keto-admin-high","tier":"Production","env":"Development","rpm":120,"rps":7},{"bucket":"keto-admin-high","tier":"Production","env":"Production","rpm":250,"rps":10},{"bucket":"keto-admin-high","tier":"Production","env":"Staging","rpm":120,"rps":7},{"bucket":"keto-admin-medium","tier":"Developer","env":"Development","rpm":100,"rps":5},{"bucket":"keto-admin-medium","tier":"Developer","env":"Production","rpm":100,"rps":5},{"bucket":"keto-admin-medium","tier":"Developer","env":"Staging","rpm":100,"rps":5},{"bucket":"keto-admin-medium","tier":"Enterprise","env":"Development","rpm":200,"rps":10},{"bucket":"keto-admin-medium","tier":"Enterprise","env":"Production","rpm":2000,"rps":70},{"bucket":"keto-admin-medium","tier":"Enterprise","env":"Staging","rpm":200,"rps":10},{"bucket":"keto-admin-medium","tier":"Growth","env":"Development","rpm":200,"rps":10},{"bucket":"keto-admin-medium","tier":"Growth","env":"Production","rpm":1000,"rps":35},{"bucket":"keto-admin-medium","tier":"Growth","env":"Staging","rpm":200,"rps":10},{"bucket":"keto-admin-medium","tier":"Production","env":"Development","rpm":200,"rps":10},{"bucket":"keto-admin-medium","tier":"Production","env":"Production","rpm":500,"rps":20},{"bucket":"keto-admin-medium","tier":"Production","env":"Staging","rpm":200,"rps":10},{"bucket":"keto-public-low","tier":"Developer","env":"Development","rpm":120,"rps":7},{"bucket":"keto-public-low","tier":"Developer","env":"Production","rpm":120,"rps":7},{"bucket":"keto-public-low","tier":"Developer","env":"Staging","rpm":120,"rps":7},{"bucket":"keto-public-low","tier":"Enterprise","env":"Development","rpm":240,"rps":10},{"bucket":"keto-public-low","tier":"Enterprise","env":"Production","rpm":18000,"rps":600},{"bucket":"keto-public-low","tier":"Enterprise","env":"Staging","rpm":240,"rps":10},{"bucket":"keto-public-low","tier":"Growth","env":"Development","rpm":240,"rps":10},{"bucket":"keto-public-low","tier":"Growth","env":"Production","rpm":9000,"rps":300},{"bucket":"keto-public-low","tier":"Growth","env":"Staging","rpm":240,"rps":10},{"bucket":"keto-public-low","tier":"Production","env":"Development","rpm":240,"rps":10},{"bucket":"keto-public-low","tier":"Production","env":"Production","rpm":1500,"rps":55},{"bucket":"keto-public-low","tier":"Production","env":"Staging","rpm":240,"rps":10},{"bucket":"kratos-admin-high","tier":"Developer","env":"Development","rpm":100,"rps":5},{"bucket":"kratos-admin-high","tier":"Developer","env":"Production","rpm":100,"rps":5},{"bucket":"kratos-admin-high","tier":"Developer","env":"Staging","rpm":100,"rps":5},{"bucket":"kratos-admin-high","tier":"Enterprise","env":"Development","rpm":200,"rps":10},{"bucket":"kratos-admin-high","tier":"Enterprise","env":"Production","rpm":2400,"rps":80},{"bucket":"kratos-admin-high","tier":"Enterprise","env":"Staging","rpm":200,"rps":10},{"bucket":"kratos-admin-high","tier":"Growth","env":"Development","rpm":200,"rps":10},{"bucket":"kratos-admin-high","tier":"Growth","env":"Production","rpm":1200,"rps":45},{"bucket":"kratos-admin-high","tier":"Growth","env":"Staging","rpm":200,"rps":10},{"bucket":"kratos-admin-high","tier":"Production","env":"Development","rpm":200,"rps":10},{"bucket":"kratos-admin-high","tier":"Production","env":"Production","rpm":400,"rps":15},{"bucket":"kratos-admin-high","tier":"Production","env":"Staging","rpm":200,"rps":10},{"bucket":"kratos-admin-low","tier":"Developer","env":"Development","rpm":100,"rps":5},{"bucket":"kratos-admin-low","tier":"Developer","env":"Production","rpm":100,"rps":5},{"bucket":"kratos-admin-low","tier":"Developer","env":"Staging","rpm":100,"rps":5},{"bucket":"kratos-admin-low","tier":"Enterprise","env":"Development","rpm":200,"rps":10},{"bucket":"kratos-admin-low","tier":"Enterprise","env":"Production","rpm":2400,"rps":80},{"bucket":"kratos-admin-low","tier":"Enterprise","env":"Staging","rpm":200,"rps":10},{"bucket":"kratos-admin-low","tier":"Growth","env":"Development","rpm":200,"rps":10},{"bucket":"kratos-admin-low","tier":"Growth","env":"Production","rpm":1200,"rps":45},{"bucket":"kratos-admin-low","tier":"Growth","env":"Staging","rpm":200,"rps":10},{"bucket":"kratos-admin-low","tier":"Production","env":"Development","rpm":200,"rps":10},{"bucket":"kratos-admin-low","tier":"Production","env":"Production","rpm":400,"rps":15},{"bucket":"kratos-admin-low","tier":"Production","env":"Staging","rpm":200,"rps":10},{"bucket":"kratos-admin-medium","tier":"Developer","env":"Development","rpm":50,"rps":3},{"bucket":"kratos-admin-medium","tier":"Developer","env":"Production","rpm":50,"rps":3},{"bucket":"kratos-admin-medium","tier":"Developer","env":"Staging","rpm":50,"rps":3},{"bucket":"kratos-admin-medium","tier":"Enterprise","env":"Development","rpm":100,"rps":5},{"bucket":"kratos-admin-medium","tier":"Enterprise","env":"Production","rpm":800,"rps":30},{"bucket":"kratos-admin-medium","tier":"Enterprise","env":"Staging","rpm":100,"rps":5},{"bucket":"kratos-admin-medium","tier":"Growth","env":"Development","rpm":100,"rps":5},{"bucket":"kratos-admin-medium","tier":"Growth","env":"Production","rpm":400,"rps":15},{"bucket":"kratos-admin-medium","tier":"Growth","env":"Staging","rpm":100,"rps":5},{"bucket":"kratos-admin-medium","tier":"Production","env":"Development","rpm":100,"rps":5},{"bucket":"kratos-admin-medium","tier":"Production","env":"Production","rpm":200,"rps":10},{"bucket":"kratos-admin-medium","tier":"Production","env":"Staging","rpm":100,"rps":5},{"bucket":"kratos-public-high","tier":"Developer","env":"Development","rpm":50,"rps":3},{"bucket":"kratos-public-high","tier":"Developer","env":"Production","rpm":50,"rps":3},{"bucket":"kratos-public-high","tier":"Developer","env":"Staging","rpm":50,"rps":3},{"bucket":"kratos-public-high","tier":"Enterprise","env":"Development","rpm":100,"rps":5},{"bucket":"kratos-public-high","tier":"Enterprise","env":"Production","rpm":1200,"rps":45},{"bucket":"kratos-public-high","tier":"Enterprise","env":"Staging","rpm":100,"rps":5},{"bucket":"kratos-public-high","tier":"Growth","env":"Development","rpm":100,"rps":5},{"bucket":"kratos-public-high","tier":"Growth","env":"Production","rpm":600,"rps":25},{"bucket":"kratos-public-high","tier":"Growth","env":"Staging","rpm":100,"rps":5},{"bucket":"kratos-public-high","tier":"Production","env":"Development","rpm":100,"rps":5},{"bucket":"kratos-public-high","tier":"Production","env":"Production","rpm":200,"rps":10},{"bucket":"kratos-public-high","tier":"Production","env":"Staging","rpm":100,"rps":5},{"bucket":"kratos-public-low","tier":"Developer","env":"Development","rpm":200,"rps":10},{"bucket":"kratos-public-low","tier":"Developer","env":"Production","rpm":200,"rps":10},{"bucket":"kratos-public-low","tier":"Developer","env":"Staging","rpm":200,"rps":10},{"bucket":"kratos-public-low","tier":"Enterprise","env":"Development","rpm":400,"rps":15},{"bucket":"kratos-public-low","tier":"Enterprise","env":"Production","rpm":21600,"rps":700},{"bucket":"kratos-public-low","tier":"Enterprise","env":"Staging","rpm":400,"rps":15},{"bucket":"kratos-public-low","tier":"Growth","env":"Development","rpm":400,"rps":15},{"bucket":"kratos-public-low","tier":"Growth","env":"Production","rpm":7200,"rps":240},{"bucket":"kratos-public-low","tier":"Growth","env":"Staging","rpm":400,"rps":15},{"bucket":"kratos-public-low","tier":"Production","env":"Development","rpm":400,"rps":15},{"bucket":"kratos-public-low","tier":"Production","env":"Production","rpm":2400,"rps":80},{"bucket":"kratos-public-low","tier":"Production","env":"Staging","rpm":400,"rps":15},{"bucket":"kratos-public-medium","tier":"Developer","env":"Development","rpm":100,"rps":5},{"bucket":"kratos-public-medium","tier":"Developer","env":"Production","rpm":100,"rps":5},{"bucket":"kratos-public-medium","tier":"Developer","env":"Staging","rpm":100,"rps":5},{"bucket":"kratos-public-medium","tier":"Enterprise","env":"Development","rpm":200,"rps":10},{"bucket":"kratos-public-medium","tier":"Enterprise","env":"Production","rpm":1600,"rps":55},{"bucket":"kratos-public-medium","tier":"Enterprise","env":"Staging","rpm":200,"rps":10},{"bucket":"kratos-public-medium","tier":"Growth","env":"Development","rpm":200,"rps":10},{"bucket":"kratos-public-medium","tier":"Growth","env":"Production","rpm":800,"rps":30},{"bucket":"kratos-public-medium","tier":"Growth","env":"Staging","rpm":200,"rps":10},{"bucket":"kratos-public-medium","tier":"Production","env":"Development","rpm":200,"rps":10},{"bucket":"kratos-public-medium","tier":"Production","env":"Production","rpm":400,"rps":15},{"bucket":"kratos-public-medium","tier":"Production","env":"Staging","rpm":200,"rps":10},{"bucket":"polis-public-low","tier":"Developer","env":"Development","rpm":15,"rps":2},{"bucket":"polis-public-low","tier":"Developer","env":"Production","rpm":15,"rps":2},{"bucket":"polis-public-low","tier":"Developer","env":"Staging","rpm":15,"rps":2},{"bucket":"polis-public-low","tier":"Enterprise","env":"Development","rpm":30,"rps":2},{"bucket":"polis-public-low","tier":"Enterprise","env":"Production","rpm":250,"rps":10},{"bucket":"polis-public-low","tier":"Enterprise","env":"Staging","rpm":30,"rps":2},{"bucket":"polis-public-low","tier":"Growth","env":"Development","rpm":30,"rps":2},{"bucket":"polis-public-low","tier":"Growth","env":"Production","rpm":120,"rps":7},{"bucket":"polis-public-low","tier":"Growth","env":"Staging","rpm":30,"rps":2},{"bucket":"polis-public-low","tier":"Production","env":"Development","rpm":30,"rps":2},{"bucket":"polis-public-low","tier":"Production","env":"Production","rpm":60,"rps":3},{"bucket":"polis-public-low","tier":"Production","env":"Staging","rpm":30,"rps":2},{"bucket":"polis-public-medium","tier":"Developer","env":"Development","rpm":60,"rps":3},{"bucket":"polis-public-medium","tier":"Developer","env":"Production","rpm":60,"rps":3},{"bucket":"polis-public-medium","tier":"Developer","env":"Staging","rpm":60,"rps":3},{"bucket":"polis-public-medium","tier":"Enterprise","env":"Development","rpm":120,"rps":7},{"bucket":"polis-public-medium","tier":"Enterprise","env":"Production","rpm":1000,"rps":35},{"bucket":"polis-public-medium","tier":"Enterprise","env":"Staging","rpm":120,"rps":7},{"bucket":"polis-public-medium","tier":"Growth","env":"Development","rpm":120,"rps":7},{"bucket":"polis-public-medium","tier":"Growth","env":"Production","rpm":500,"rps":20},{"bucket":"polis-public-medium","tier":"Growth","env":"Staging","rpm":120,"rps":7},{"bucket":"polis-public-medium","tier":"Production","env":"Development","rpm":120,"rps":7},{"bucket":"polis-public-medium","tier":"Production","env":"Production","rpm":250,"rps":10},{"bucket":"polis-public-medium","tier":"Production","env":"Staging","rpm":120,"rps":7}]} \ No newline at end of file +{ + "endpoints": [ + { + "method": "GET", + "path": "/.well-known/jwks.json", + "bucket": "hydra-public-low" + }, + { + "method": "GET", + "path": "/.well-known/openid-configuration", + "bucket": "hydra-public-low" + }, + { + "method": "GET", + "path": "/.well-known/ory/webauthn.js", + "bucket": "hydra-public-low" + }, + { + "method": "GET", + "path": "/admin/clients", + "bucket": "hydra-admin-medium" + }, + { + "method": "POST", + "path": "/admin/clients", + "bucket": "hydra-admin-high" + }, + { + "method": "GET", + "path": "/admin/clients/{id}", + "bucket": "hydra-admin-low" + }, + { + "method": "DELETE", + "path": "/admin/clients/{id}", + "bucket": "hydra-admin-high" + }, + { + "method": "PATCH", + "path": "/admin/clients/{id}", + "bucket": "hydra-admin-high" + }, + { + "method": "PUT", + "path": "/admin/clients/{id}", + "bucket": "hydra-admin-high" + }, + { + "method": "HEAD", + "path": "/.well-known/openid-configuration", + "bucket": "hydra-public-low" + }, + { + "method": "PUT", + "path": "/admin/clients/{id}/lifespans", + "bucket": "hydra-admin-high" + }, + { + "method": "GET", + "path": "/admin/keys/{set}", + "bucket": "hydra-admin-medium" + }, + { + "method": "DELETE", + "path": "/admin/keys/{set}", + "bucket": "hydra-admin-high" + }, + { + "method": "POST", + "path": "/admin/keys/{set}", + "bucket": "hydra-admin-high" + }, + { + "method": "PUT", + "path": "/admin/keys/{set}", + "bucket": "hydra-admin-high" + }, + { + "method": "GET", + "path": "/admin/keys/{set}/{kid}", + "bucket": "hydra-admin-medium" + }, + { + "method": "DELETE", + "path": "/admin/keys/{set}/{kid}", + "bucket": "hydra-admin-high" + }, + { + "method": "PUT", + "path": "/admin/keys/{set}/{kid}", + "bucket": "hydra-admin-high" + }, + { + "method": "GET", + "path": "/admin/oauth2/auth/requests/consent", + "bucket": "hydra-admin-low" + }, + { + "method": "PUT", + "path": "/admin/oauth2/auth/requests/consent/accept", + "bucket": "hydra-admin-low" + }, + { + "method": "PUT", + "path": "/admin/oauth2/auth/requests/consent/reject", + "bucket": "hydra-admin-low" + }, + { + "method": "PUT", + "path": "/admin/oauth2/auth/requests/device/accept", + "bucket": "hydra-admin-low" + }, + { + "method": "GET", + "path": "/admin/oauth2/auth/requests/login", + "bucket": "hydra-admin-low" + }, + { + "method": "PUT", + "path": "/admin/oauth2/auth/requests/login/accept", + "bucket": "hydra-admin-low" + }, + { + "method": "PUT", + "path": "/admin/oauth2/auth/requests/login/reject", + "bucket": "hydra-admin-low" + }, + { + "method": "GET", + "path": "/admin/oauth2/auth/requests/logout", + "bucket": "hydra-admin-low" + }, + { + "method": "PUT", + "path": "/admin/oauth2/auth/requests/logout/accept", + "bucket": "hydra-admin-low" + }, + { + "method": "PUT", + "path": "/admin/oauth2/auth/requests/logout/reject", + "bucket": "hydra-admin-low" + }, + { + "method": "GET", + "path": "/admin/oauth2/auth/sessions/consent", + "bucket": "hydra-admin-low" + }, + { + "method": "DELETE", + "path": "/admin/oauth2/auth/sessions/consent", + "bucket": "hydra-admin-high" + }, + { + "method": "DELETE", + "path": "/admin/oauth2/auth/sessions/login", + "bucket": "hydra-admin-high" + }, + { + "method": "POST", + "path": "/admin/oauth2/introspect", + "bucket": "hydra-admin-low" + }, + { + "method": "DELETE", + "path": "/admin/oauth2/tokens", + "bucket": "hydra-admin-high" + }, + { + "method": "GET", + "path": "/admin/trust/grants/jwt-bearer/issuers", + "bucket": "hydra-admin-medium" + }, + { + "method": "POST", + "path": "/admin/trust/grants/jwt-bearer/issuers", + "bucket": "hydra-admin-high" + }, + { + "method": "GET", + "path": "/admin/trust/grants/jwt-bearer/issuers/{id}", + "bucket": "hydra-admin-medium" + }, + { + "method": "DELETE", + "path": "/admin/trust/grants/jwt-bearer/issuers/{id}", + "bucket": "hydra-admin-high" + }, + { + "method": "OPTIONS", + "path": "/admin/clients", + "bucket": "hydra-admin-low" + }, + { + "method": "OPTIONS", + "path": "/admin/clients/{id}", + "bucket": "hydra-admin-low" + }, + { + "method": "POST", + "path": "/credentials", + "bucket": "hydra-admin-medium" + }, + { + "method": "GET", + "path": "/oauth2/auth", + "bucket": "hydra-public-medium" + }, + { "method": "HEAD", "path": "/oauth2/auth", "bucket": "hydra-public-low" }, + { + "method": "POST", + "path": "/oauth2/device/auth", + "bucket": "hydra-public-low" + }, + { + "method": "GET", + "path": "/oauth2/device/verify", + "bucket": "hydra-admin-low" + }, + { + "method": "OPTIONS", + "path": "/oauth2/auth", + "bucket": "hydra-public-low" + }, + { + "method": "POST", + "path": "/oauth2/register", + "bucket": "hydra-public-high" + }, + { + "method": "GET", + "path": "/oauth2/register/{id}", + "bucket": "hydra-admin-low" + }, + { + "method": "DELETE", + "path": "/oauth2/register/{id}", + "bucket": "hydra-public-high" + }, + { + "method": "PUT", + "path": "/oauth2/register/{id}", + "bucket": "hydra-public-high" + }, + { + "method": "POST", + "path": "/oauth2/revoke", + "bucket": "hydra-public-medium" + }, + { + "method": "GET", + "path": "/oauth2/sessions/logout", + "bucket": "hydra-public-medium" + }, + { + "method": "POST", + "path": "/oauth2/auth", + "bucket": "hydra-public-medium" + }, + { + "method": "POST", + "path": "/oauth2/token", + "bucket": "hydra-public-medium" + }, + { + "method": "GET", + "path": "/oauth2/consent", + "bucket": "hydra-public-low" + }, + { + "method": "GET", + "path": "/oauth2/fallbacks/logout/callback", + "bucket": "hydra-public-low" + }, + { + "method": "POST", + "path": "/oauth2/sessions/logout", + "bucket": "hydra-public-medium" + }, + { + "method": "OPTIONS", + "path": "/oauth2/token", + "bucket": "hydra-public-low" + }, + { "method": "GET", "path": "/userinfo", "bucket": "hydra-public-medium" }, + { + "method": "DELETE", + "path": "/admin/relation-tuples", + "bucket": "keto-admin-high" + }, + { + "method": "PATCH", + "path": "/admin/relation-tuples", + "bucket": "keto-admin-high" + }, + { + "method": "PUT", + "path": "/admin/relation-tuples", + "bucket": "keto-admin-high" + }, + { "method": "GET", "path": "/namespaces", "bucket": "keto-admin-high" }, + { + "method": "POST", + "path": "/opl/syntax/check", + "bucket": "keto-admin-medium" + }, + { + "method": "POST", + "path": "/ory.keto.relation_tuples.v1alpha2.CheckService/BatchCheck", + "bucket": "keto-public-low" + }, + { + "method": "POST", + "path": "/ory.keto.relation_tuples.v1alpha2.CheckService/Check", + "bucket": "keto-public-low" + }, + { + "method": "POST", + "path": "/ory.keto.relation_tuples.v1alpha2.WriteService/TransactRelationTuples", + "bucket": "keto-admin-high" + }, + { + "method": "GET", + "path": "/relation-tuples", + "bucket": "keto-admin-medium" + }, + { + "method": "POST", + "path": "/relation-tuples/batch/check", + "bucket": "keto-public-low" + }, + { + "method": "GET", + "path": "/relation-tuples/check", + "bucket": "keto-public-low" + }, + { + "method": "POST", + "path": "/relation-tuples/check", + "bucket": "keto-public-low" + }, + { + "method": "GET", + "path": "/relation-tuples/check/openapi", + "bucket": "keto-public-low" + }, + { + "method": "POST", + "path": "/relation-tuples/check/openapi", + "bucket": "keto-public-low" + }, + { + "method": "GET", + "path": "/relation-tuples/expand", + "bucket": "keto-admin-medium" + }, + { + "method": "GET", + "path": "/admin/courier/messages", + "bucket": "kratos-admin-high" + }, + { + "method": "PATCH", + "path": "/admin/identities", + "bucket": "kratos-admin-high" + }, + { + "method": "POST", + "path": "/admin/identities", + "bucket": "kratos-admin-high" + }, + { + "method": "DELETE", + "path": "/admin/identities/{id}", + "bucket": "kratos-admin-high" + }, + { + "method": "PATCH", + "path": "/admin/identities/{id}", + "bucket": "kratos-admin-high" + }, + { + "method": "PUT", + "path": "/admin/identities/{id}", + "bucket": "kratos-admin-high" + }, + { + "method": "DELETE", + "path": "/admin/identities/{id}/credentials/{type}", + "bucket": "kratos-admin-high" + }, + { + "method": "DELETE", + "path": "/admin/identities/{id}/sessions", + "bucket": "kratos-admin-high" + }, + { + "method": "POST", + "path": "/admin/recovery/code", + "bucket": "kratos-admin-high" + }, + { + "method": "POST", + "path": "/admin/recovery/link", + "bucket": "kratos-admin-high" + }, + { + "method": "DELETE", + "path": "/admin/sessions/{id}", + "bucket": "kratos-admin-high" + }, + { + "method": "PATCH", + "path": "/admin/sessions/{id}/extend", + "bucket": "kratos-admin-high" + }, + { + "method": "POST", + "path": "/scim/{client}/v2/Groups", + "bucket": "kratos-admin-high" + }, + { + "method": "PUT", + "path": "/scim/{client}/v2/Groups/{id}", + "bucket": "kratos-admin-high" + }, + { + "method": "PATCH", + "path": "/scim/{client}/v2/Groups/{id}", + "bucket": "kratos-admin-high" + }, + { + "method": "DELETE", + "path": "/scim/{client}/v2/Groups/{id}", + "bucket": "kratos-admin-high" + }, + { + "method": "POST", + "path": "/scim/{client}/v2/Users", + "bucket": "kratos-admin-high" + }, + { + "method": "PUT", + "path": "/scim/{client}/v2/Users/{id}", + "bucket": "kratos-admin-high" + }, + { + "method": "PATCH", + "path": "/scim/{client}/v2/Users/{id}", + "bucket": "kratos-admin-high" + }, + { + "method": "DELETE", + "path": "/scim/{client}/v2/Users/{id}", + "bucket": "kratos-admin-high" + }, + { + "method": "GET", + "path": "/admin/identities/{id}", + "bucket": "kratos-admin-low" + }, + { + "method": "GET", + "path": "/admin/sessions/{id}", + "bucket": "kratos-admin-low" + }, + { + "method": "OPTIONS", + "path": "/admin/identities/{id}", + "bucket": "kratos-admin-low" + }, + { + "method": "GET", + "path": "/admin/courier/messages/{id}", + "bucket": "kratos-admin-medium" + }, + { + "method": "GET", + "path": "/admin/identities", + "bucket": "kratos-admin-medium" + }, + { + "method": "GET", + "path": "/admin/identities/{id}/sessions", + "bucket": "kratos-admin-medium" + }, + { + "method": "GET", + "path": "/admin/identities/by/external/{externalID}", + "bucket": "kratos-admin-medium" + }, + { + "method": "GET", + "path": "/admin/sessions", + "bucket": "kratos-admin-medium" + }, + { "method": "GET", "path": "/schemas", "bucket": "kratos-admin-medium" }, + { + "method": "GET", + "path": "/schemas/{id}", + "bucket": "kratos-admin-medium" + }, + { + "method": "GET", + "path": "/scim/{client}/v2/Groups", + "bucket": "kratos-admin-medium" + }, + { + "method": "GET", + "path": "/scim/{client}/v2/Groups/{id}", + "bucket": "kratos-admin-medium" + }, + { + "method": "GET", + "path": "/scim/{client}/v2/Schemas", + "bucket": "kratos-admin-medium" + }, + { + "method": "GET", + "path": "/scim/{client}/v2/Schemas/{id}", + "bucket": "kratos-admin-medium" + }, + { + "method": "GET", + "path": "/scim/{client}/v2/ServiceProviderConfig", + "bucket": "kratos-admin-medium" + }, + { + "method": "GET", + "path": "/scim/{client}/v2/Users", + "bucket": "kratos-admin-medium" + }, + { + "method": "GET", + "path": "/scim/{client}/v2/Users/{id}", + "bucket": "kratos-admin-medium" + }, + { + "method": "GET", + "path": "/self-service/errors", + "bucket": "kratos-public-low" + }, + { + "method": "GET", + "path": "/self-service/fed-cm/parameters", + "bucket": "kratos-public-low" + }, + { + "method": "POST", + "path": "/self-service/fed-cm/token", + "bucket": "kratos-public-high" + }, + { + "method": "POST", + "path": "/self-service/login", + "bucket": "kratos-public-high" + }, + { + "method": "GET", + "path": "/self-service/login/api", + "bucket": "kratos-public-medium" + }, + { + "method": "GET", + "path": "/self-service/login/browser", + "bucket": "kratos-public-medium" + }, + { + "method": "GET", + "path": "/self-service/login/flows", + "bucket": "kratos-public-low" + }, + { + "method": "HEAD", + "path": "/self-service/fed-cm/parameters", + "bucket": "kratos-public-low" + }, + { + "method": "GET", + "path": "/self-service/logout", + "bucket": "kratos-public-low" + }, + { + "method": "OPTIONS", + "path": "/self-service/fed-cm/token", + "bucket": "kratos-public-low" + }, + { + "method": "DELETE", + "path": "/self-service/logout/api", + "bucket": "kratos-public-medium" + }, + { + "method": "GET", + "path": "/self-service/logout/browser", + "bucket": "kratos-public-medium" + }, + { + "method": "GET", + "path": "/self-service/login", + "bucket": "kratos-public-low" + }, + { + "method": "OPTIONS", + "path": "/self-service/login", + "bucket": "kratos-public-low" + }, + { + "method": "GET", + "path": "/self-service/methods/oidc/callback/{provider_id}", + "bucket": "kratos-public-medium" + }, + { + "method": "GET", + "path": "/self-service/methods/oidc/organizations/{organization_id}", + "bucket": "kratos-public-medium" + }, + { + "method": "GET", + "path": "/self-service/methods/saml/callback/{provider_id}", + "bucket": "kratos-public-medium" + }, + { + "method": "GET", + "path": "/self-service/methods/saml/organizations/{organization_id}", + "bucket": "kratos-public-medium" + }, + { + "method": "POST", + "path": "/self-service/recovery", + "bucket": "kratos-public-high" + }, + { + "method": "HEAD", + "path": "/self-service/login/browser", + "bucket": "kratos-public-low" + }, + { + "method": "OPTIONS", + "path": "/self-service/login/browser", + "bucket": "kratos-public-low" + }, + { + "method": "POST", + "path": "/self-service/login/browser", + "bucket": "kratos-public-medium" + }, + { + "method": "GET", + "path": "/self-service/recovery/api", + "bucket": "kratos-public-medium" + }, + { + "method": "GET", + "path": "/self-service/recovery/browser", + "bucket": "kratos-public-medium" + }, + { + "method": "OPTIONS", + "path": "/self-service/login/flows", + "bucket": "kratos-public-low" + }, + { + "method": "GET", + "path": "/self-service/recovery/flows", + "bucket": "kratos-public-low" + }, + { + "method": "OPTIONS", + "path": "/self-service/logout", + "bucket": "kratos-public-low" + }, + { + "method": "POST", + "path": "/self-service/registration", + "bucket": "kratos-public-high" + }, + { + "method": "OPTIONS", + "path": "/self-service/logout/browser", + "bucket": "kratos-public-low" + }, + { + "method": "GET", + "path": "/self-service/methods/oidc/callback", + "bucket": "kratos-public-low" + }, + { + "method": "GET", + "path": "/self-service/registration/api", + "bucket": "kratos-public-medium" + }, + { + "method": "GET", + "path": "/self-service/registration/browser", + "bucket": "kratos-public-medium" + }, + { + "method": "GET", + "path": "/self-service/registration/flows", + "bucket": "kratos-public-low" + }, + { + "method": "POST", + "path": "/self-service/settings", + "bucket": "kratos-public-high" + }, + { + "method": "HEAD", + "path": "/self-service/methods/oidc/callback/{provider_id}", + "bucket": "kratos-public-low" + }, + { + "method": "GET", + "path": "/self-service/recovery", + "bucket": "kratos-public-low" + }, + { + "method": "GET", + "path": "/self-service/settings/api", + "bucket": "kratos-public-medium" + }, + { + "method": "GET", + "path": "/self-service/settings/browser", + "bucket": "kratos-public-medium" + }, + { + "method": "GET", + "path": "/self-service/settings/flows", + "bucket": "kratos-public-low" + }, + { + "method": "POST", + "path": "/self-service/verification", + "bucket": "kratos-public-high" + }, + { + "method": "HEAD", + "path": "/self-service/recovery", + "bucket": "kratos-public-low" + }, + { + "method": "OPTIONS", + "path": "/self-service/recovery", + "bucket": "kratos-public-low" + }, + { + "method": "HEAD", + "path": "/self-service/recovery/browser", + "bucket": "kratos-public-low" + }, + { + "method": "GET", + "path": "/self-service/verification/api", + "bucket": "kratos-public-medium" + }, + { + "method": "GET", + "path": "/self-service/verification/browser", + "bucket": "kratos-public-medium" + }, + { + "method": "OPTIONS", + "path": "/self-service/recovery/browser", + "bucket": "kratos-public-low" + }, + { + "method": "GET", + "path": "/self-service/verification/flows", + "bucket": "kratos-public-low" + }, + { + "method": "OPTIONS", + "path": "/self-service/recovery/flows", + "bucket": "kratos-public-low" + }, + { "method": "GET", "path": "/sessions", "bucket": "kratos-public-medium" }, + { "method": "DELETE", "path": "/sessions", "bucket": "kratos-public-high" }, + { + "method": "DELETE", + "path": "/sessions/{id}", + "bucket": "kratos-public-high" + }, + { + "method": "GET", + "path": "/sessions/token-exchange", + "bucket": "kratos-public-medium" + }, + { + "method": "GET", + "path": "/self-service/registration", + "bucket": "kratos-public-low" + }, + { + "method": "OPTIONS", + "path": "/self-service/registration", + "bucket": "kratos-public-low" + }, + { + "method": "HEAD", + "path": "/self-service/registration/browser", + "bucket": "kratos-public-low" + }, + { + "method": "GET", + "path": "/sessions/whoami", + "bucket": "kratos-public-low" + }, + { + "method": "OPTIONS", + "path": "/self-service/registration/browser", + "bucket": "kratos-public-low" + }, + { + "method": "GET", + "path": "/self-service/settings", + "bucket": "kratos-public-low" + }, + { + "method": "OPTIONS", + "path": "/self-service/settings", + "bucket": "kratos-public-low" + }, + { + "method": "GET", + "path": "/self-service/verification", + "bucket": "kratos-public-low" + }, + { + "method": "HEAD", + "path": "/self-service/verification", + "bucket": "kratos-public-low" + }, + { + "method": "OPTIONS", + "path": "/self-service/verification", + "bucket": "kratos-public-low" + }, + { + "method": "HEAD", + "path": "/self-service/verification/browser", + "bucket": "kratos-public-low" + }, + { + "method": "OPTIONS", + "path": "/self-service/verification/flows", + "bucket": "kratos-public-low" + }, + { "method": "OPTIONS", "path": "/sessions", "bucket": "kratos-public-low" }, + { + "method": "GET", + "path": "/saml/.well-known/idp-metadata", + "bucket": "polis-public-low" + }, + { + "method": "GET", + "path": "/saml/.well-known/saml.cer", + "bucket": "polis-public-low" + }, + { + "method": "GET", + "path": "/saml/.well-known/sp-metadata", + "bucket": "polis-public-low" + }, + { + "method": "GET", + "path": "/saml/api/error", + "bucket": "polis-public-low" + }, + { + "method": "POST", + "path": "/saml/api/identity-federation/sso", + "bucket": "polis-public-medium" + }, + { + "method": "GET", + "path": "/saml/api/identity-federation/sso", + "bucket": "polis-public-medium" + }, + { + "method": "POST", + "path": "/saml/api/oauth/authorize", + "bucket": "polis-public-medium" + }, + { + "method": "GET", + "path": "/saml/api/oauth/authorize", + "bucket": "polis-public-medium" + }, + { + "method": "GET", + "path": "/saml/api/oauth/oidc", + "bucket": "polis-public-medium" + }, + { + "method": "POST", + "path": "/saml/api/oauth/saml", + "bucket": "polis-public-medium" + } + ], + "thresholds": [ + { + "bucket": "hydra-admin-high", + "tier": "Developer", + "env": "Development", + "rpm": 20, + "rps": 2 + }, + { + "bucket": "hydra-admin-high", + "tier": "Developer", + "env": "Production", + "rpm": 20, + "rps": 2 + }, + { + "bucket": "hydra-admin-high", + "tier": "Developer", + "env": "Staging", + "rpm": 20, + "rps": 2 + }, + { + "bucket": "hydra-admin-high", + "tier": "Enterprise", + "env": "Development", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-admin-high", + "tier": "Enterprise", + "env": "Production", + "rpm": 320, + "rps": 10 + }, + { + "bucket": "hydra-admin-high", + "tier": "Enterprise", + "env": "Staging", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-admin-high", + "tier": "Growth", + "env": "Development", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-admin-high", + "tier": "Growth", + "env": "Production", + "rpm": 160, + "rps": 7 + }, + { + "bucket": "hydra-admin-high", + "tier": "Growth", + "env": "Staging", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-admin-high", + "tier": "Production", + "env": "Development", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-admin-high", + "tier": "Production", + "env": "Production", + "rpm": 80, + "rps": 4 + }, + { + "bucket": "hydra-admin-high", + "tier": "Production", + "env": "Staging", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-admin-low", + "tier": "Developer", + "env": "Development", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-admin-low", + "tier": "Developer", + "env": "Production", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-admin-low", + "tier": "Developer", + "env": "Staging", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-admin-low", + "tier": "Enterprise", + "env": "Development", + "rpm": 80, + "rps": 4 + }, + { + "bucket": "hydra-admin-low", + "tier": "Enterprise", + "env": "Production", + "rpm": 4800, + "rps": 160 + }, + { + "bucket": "hydra-admin-low", + "tier": "Enterprise", + "env": "Staging", + "rpm": 80, + "rps": 4 + }, + { + "bucket": "hydra-admin-low", + "tier": "Growth", + "env": "Development", + "rpm": 80, + "rps": 4 + }, + { + "bucket": "hydra-admin-low", + "tier": "Growth", + "env": "Production", + "rpm": 2400, + "rps": 80 + }, + { + "bucket": "hydra-admin-low", + "tier": "Growth", + "env": "Staging", + "rpm": 80, + "rps": 4 + }, + { + "bucket": "hydra-admin-low", + "tier": "Production", + "env": "Development", + "rpm": 80, + "rps": 4 + }, + { + "bucket": "hydra-admin-low", + "tier": "Production", + "env": "Production", + "rpm": 250, + "rps": 10 + }, + { + "bucket": "hydra-admin-low", + "tier": "Production", + "env": "Staging", + "rpm": 80, + "rps": 4 + }, + { + "bucket": "hydra-admin-medium", + "tier": "Developer", + "env": "Development", + "rpm": 20, + "rps": 2 + }, + { + "bucket": "hydra-admin-medium", + "tier": "Developer", + "env": "Production", + "rpm": 20, + "rps": 2 + }, + { + "bucket": "hydra-admin-medium", + "tier": "Developer", + "env": "Staging", + "rpm": 20, + "rps": 2 + }, + { + "bucket": "hydra-admin-medium", + "tier": "Enterprise", + "env": "Development", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-admin-medium", + "tier": "Enterprise", + "env": "Production", + "rpm": 320, + "rps": 10 + }, + { + "bucket": "hydra-admin-medium", + "tier": "Enterprise", + "env": "Staging", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-admin-medium", + "tier": "Growth", + "env": "Development", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-admin-medium", + "tier": "Growth", + "env": "Production", + "rpm": 160, + "rps": 7 + }, + { + "bucket": "hydra-admin-medium", + "tier": "Growth", + "env": "Staging", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-admin-medium", + "tier": "Production", + "env": "Development", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-admin-medium", + "tier": "Production", + "env": "Production", + "rpm": 80, + "rps": 4 + }, + { + "bucket": "hydra-admin-medium", + "tier": "Production", + "env": "Staging", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-public-high", + "tier": "Developer", + "env": "Development", + "rpm": 20, + "rps": 2 + }, + { + "bucket": "hydra-public-high", + "tier": "Developer", + "env": "Production", + "rpm": 20, + "rps": 2 + }, + { + "bucket": "hydra-public-high", + "tier": "Developer", + "env": "Staging", + "rpm": 20, + "rps": 2 + }, + { + "bucket": "hydra-public-high", + "tier": "Enterprise", + "env": "Development", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-public-high", + "tier": "Enterprise", + "env": "Production", + "rpm": 320, + "rps": 10 + }, + { + "bucket": "hydra-public-high", + "tier": "Enterprise", + "env": "Staging", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-public-high", + "tier": "Growth", + "env": "Development", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-public-high", + "tier": "Growth", + "env": "Production", + "rpm": 160, + "rps": 7 + }, + { + "bucket": "hydra-public-high", + "tier": "Growth", + "env": "Staging", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-public-high", + "tier": "Production", + "env": "Development", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-public-high", + "tier": "Production", + "env": "Production", + "rpm": 80, + "rps": 4 + }, + { + "bucket": "hydra-public-high", + "tier": "Production", + "env": "Staging", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-public-low", + "tier": "Developer", + "env": "Development", + "rpm": 60, + "rps": 3 + }, + { + "bucket": "hydra-public-low", + "tier": "Developer", + "env": "Production", + "rpm": 60, + "rps": 3 + }, + { + "bucket": "hydra-public-low", + "tier": "Developer", + "env": "Staging", + "rpm": 60, + "rps": 3 + }, + { + "bucket": "hydra-public-low", + "tier": "Enterprise", + "env": "Development", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "hydra-public-low", + "tier": "Enterprise", + "env": "Production", + "rpm": 1500, + "rps": 55 + }, + { + "bucket": "hydra-public-low", + "tier": "Enterprise", + "env": "Staging", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "hydra-public-low", + "tier": "Growth", + "env": "Development", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "hydra-public-low", + "tier": "Growth", + "env": "Production", + "rpm": 720, + "rps": 30 + }, + { + "bucket": "hydra-public-low", + "tier": "Growth", + "env": "Staging", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "hydra-public-low", + "tier": "Production", + "env": "Development", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "hydra-public-low", + "tier": "Production", + "env": "Production", + "rpm": 250, + "rps": 10 + }, + { + "bucket": "hydra-public-low", + "tier": "Production", + "env": "Staging", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "hydra-public-medium", + "tier": "Developer", + "env": "Development", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-public-medium", + "tier": "Developer", + "env": "Production", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-public-medium", + "tier": "Developer", + "env": "Staging", + "rpm": 40, + "rps": 3 + }, + { + "bucket": "hydra-public-medium", + "tier": "Enterprise", + "env": "Development", + "rpm": 80, + "rps": 4 + }, + { + "bucket": "hydra-public-medium", + "tier": "Enterprise", + "env": "Production", + "rpm": 3000, + "rps": 100 + }, + { + "bucket": "hydra-public-medium", + "tier": "Enterprise", + "env": "Staging", + "rpm": 80, + "rps": 4 + }, + { + "bucket": "hydra-public-medium", + "tier": "Growth", + "env": "Development", + "rpm": 80, + "rps": 4 + }, + { + "bucket": "hydra-public-medium", + "tier": "Growth", + "env": "Production", + "rpm": 1000, + "rps": 35 + }, + { + "bucket": "hydra-public-medium", + "tier": "Growth", + "env": "Staging", + "rpm": 80, + "rps": 4 + }, + { + "bucket": "hydra-public-medium", + "tier": "Production", + "env": "Development", + "rpm": 80, + "rps": 4 + }, + { + "bucket": "hydra-public-medium", + "tier": "Production", + "env": "Production", + "rpm": 320, + "rps": 10 + }, + { + "bucket": "hydra-public-medium", + "tier": "Production", + "env": "Staging", + "rpm": 80, + "rps": 4 + }, + { + "bucket": "keto-admin-high", + "tier": "Developer", + "env": "Development", + "rpm": 60, + "rps": 3 + }, + { + "bucket": "keto-admin-high", + "tier": "Developer", + "env": "Production", + "rpm": 60, + "rps": 3 + }, + { + "bucket": "keto-admin-high", + "tier": "Developer", + "env": "Staging", + "rpm": 60, + "rps": 3 + }, + { + "bucket": "keto-admin-high", + "tier": "Enterprise", + "env": "Development", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "keto-admin-high", + "tier": "Enterprise", + "env": "Production", + "rpm": 1000, + "rps": 35 + }, + { + "bucket": "keto-admin-high", + "tier": "Enterprise", + "env": "Staging", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "keto-admin-high", + "tier": "Growth", + "env": "Development", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "keto-admin-high", + "tier": "Growth", + "env": "Production", + "rpm": 250, + "rps": 10 + }, + { + "bucket": "keto-admin-high", + "tier": "Growth", + "env": "Staging", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "keto-admin-high", + "tier": "Production", + "env": "Development", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "keto-admin-high", + "tier": "Production", + "env": "Production", + "rpm": 250, + "rps": 10 + }, + { + "bucket": "keto-admin-high", + "tier": "Production", + "env": "Staging", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "keto-admin-medium", + "tier": "Developer", + "env": "Development", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "keto-admin-medium", + "tier": "Developer", + "env": "Production", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "keto-admin-medium", + "tier": "Developer", + "env": "Staging", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "keto-admin-medium", + "tier": "Enterprise", + "env": "Development", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "keto-admin-medium", + "tier": "Enterprise", + "env": "Production", + "rpm": 2000, + "rps": 70 + }, + { + "bucket": "keto-admin-medium", + "tier": "Enterprise", + "env": "Staging", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "keto-admin-medium", + "tier": "Growth", + "env": "Development", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "keto-admin-medium", + "tier": "Growth", + "env": "Production", + "rpm": 1000, + "rps": 35 + }, + { + "bucket": "keto-admin-medium", + "tier": "Growth", + "env": "Staging", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "keto-admin-medium", + "tier": "Production", + "env": "Development", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "keto-admin-medium", + "tier": "Production", + "env": "Production", + "rpm": 500, + "rps": 20 + }, + { + "bucket": "keto-admin-medium", + "tier": "Production", + "env": "Staging", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "keto-public-low", + "tier": "Developer", + "env": "Development", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "keto-public-low", + "tier": "Developer", + "env": "Production", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "keto-public-low", + "tier": "Developer", + "env": "Staging", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "keto-public-low", + "tier": "Enterprise", + "env": "Development", + "rpm": 240, + "rps": 10 + }, + { + "bucket": "keto-public-low", + "tier": "Enterprise", + "env": "Production", + "rpm": 18000, + "rps": 600 + }, + { + "bucket": "keto-public-low", + "tier": "Enterprise", + "env": "Staging", + "rpm": 240, + "rps": 10 + }, + { + "bucket": "keto-public-low", + "tier": "Growth", + "env": "Development", + "rpm": 240, + "rps": 10 + }, + { + "bucket": "keto-public-low", + "tier": "Growth", + "env": "Production", + "rpm": 9000, + "rps": 300 + }, + { + "bucket": "keto-public-low", + "tier": "Growth", + "env": "Staging", + "rpm": 240, + "rps": 10 + }, + { + "bucket": "keto-public-low", + "tier": "Production", + "env": "Development", + "rpm": 240, + "rps": 10 + }, + { + "bucket": "keto-public-low", + "tier": "Production", + "env": "Production", + "rpm": 1500, + "rps": 55 + }, + { + "bucket": "keto-public-low", + "tier": "Production", + "env": "Staging", + "rpm": 240, + "rps": 10 + }, + { + "bucket": "kratos-admin-high", + "tier": "Developer", + "env": "Development", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-admin-high", + "tier": "Developer", + "env": "Production", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-admin-high", + "tier": "Developer", + "env": "Staging", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-admin-high", + "tier": "Enterprise", + "env": "Development", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-admin-high", + "tier": "Enterprise", + "env": "Production", + "rpm": 2400, + "rps": 80 + }, + { + "bucket": "kratos-admin-high", + "tier": "Enterprise", + "env": "Staging", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-admin-high", + "tier": "Growth", + "env": "Development", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-admin-high", + "tier": "Growth", + "env": "Production", + "rpm": 1200, + "rps": 45 + }, + { + "bucket": "kratos-admin-high", + "tier": "Growth", + "env": "Staging", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-admin-high", + "tier": "Production", + "env": "Development", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-admin-high", + "tier": "Production", + "env": "Production", + "rpm": 400, + "rps": 15 + }, + { + "bucket": "kratos-admin-high", + "tier": "Production", + "env": "Staging", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-admin-low", + "tier": "Developer", + "env": "Development", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-admin-low", + "tier": "Developer", + "env": "Production", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-admin-low", + "tier": "Developer", + "env": "Staging", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-admin-low", + "tier": "Enterprise", + "env": "Development", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-admin-low", + "tier": "Enterprise", + "env": "Production", + "rpm": 2400, + "rps": 80 + }, + { + "bucket": "kratos-admin-low", + "tier": "Enterprise", + "env": "Staging", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-admin-low", + "tier": "Growth", + "env": "Development", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-admin-low", + "tier": "Growth", + "env": "Production", + "rpm": 1200, + "rps": 45 + }, + { + "bucket": "kratos-admin-low", + "tier": "Growth", + "env": "Staging", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-admin-low", + "tier": "Production", + "env": "Development", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-admin-low", + "tier": "Production", + "env": "Production", + "rpm": 400, + "rps": 15 + }, + { + "bucket": "kratos-admin-low", + "tier": "Production", + "env": "Staging", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-admin-medium", + "tier": "Developer", + "env": "Development", + "rpm": 50, + "rps": 3 + }, + { + "bucket": "kratos-admin-medium", + "tier": "Developer", + "env": "Production", + "rpm": 50, + "rps": 3 + }, + { + "bucket": "kratos-admin-medium", + "tier": "Developer", + "env": "Staging", + "rpm": 50, + "rps": 3 + }, + { + "bucket": "kratos-admin-medium", + "tier": "Enterprise", + "env": "Development", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-admin-medium", + "tier": "Enterprise", + "env": "Production", + "rpm": 800, + "rps": 30 + }, + { + "bucket": "kratos-admin-medium", + "tier": "Enterprise", + "env": "Staging", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-admin-medium", + "tier": "Growth", + "env": "Development", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-admin-medium", + "tier": "Growth", + "env": "Production", + "rpm": 400, + "rps": 15 + }, + { + "bucket": "kratos-admin-medium", + "tier": "Growth", + "env": "Staging", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-admin-medium", + "tier": "Production", + "env": "Development", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-admin-medium", + "tier": "Production", + "env": "Production", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-admin-medium", + "tier": "Production", + "env": "Staging", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-public-high", + "tier": "Developer", + "env": "Development", + "rpm": 50, + "rps": 3 + }, + { + "bucket": "kratos-public-high", + "tier": "Developer", + "env": "Production", + "rpm": 50, + "rps": 3 + }, + { + "bucket": "kratos-public-high", + "tier": "Developer", + "env": "Staging", + "rpm": 50, + "rps": 3 + }, + { + "bucket": "kratos-public-high", + "tier": "Enterprise", + "env": "Development", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-public-high", + "tier": "Enterprise", + "env": "Production", + "rpm": 1200, + "rps": 45 + }, + { + "bucket": "kratos-public-high", + "tier": "Enterprise", + "env": "Staging", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-public-high", + "tier": "Growth", + "env": "Development", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-public-high", + "tier": "Growth", + "env": "Production", + "rpm": 600, + "rps": 25 + }, + { + "bucket": "kratos-public-high", + "tier": "Growth", + "env": "Staging", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-public-high", + "tier": "Production", + "env": "Development", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-public-high", + "tier": "Production", + "env": "Production", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-public-high", + "tier": "Production", + "env": "Staging", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-public-low", + "tier": "Developer", + "env": "Development", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-public-low", + "tier": "Developer", + "env": "Production", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-public-low", + "tier": "Developer", + "env": "Staging", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-public-low", + "tier": "Enterprise", + "env": "Development", + "rpm": 400, + "rps": 15 + }, + { + "bucket": "kratos-public-low", + "tier": "Enterprise", + "env": "Production", + "rpm": 21600, + "rps": 700 + }, + { + "bucket": "kratos-public-low", + "tier": "Enterprise", + "env": "Staging", + "rpm": 400, + "rps": 15 + }, + { + "bucket": "kratos-public-low", + "tier": "Growth", + "env": "Development", + "rpm": 400, + "rps": 15 + }, + { + "bucket": "kratos-public-low", + "tier": "Growth", + "env": "Production", + "rpm": 7200, + "rps": 240 + }, + { + "bucket": "kratos-public-low", + "tier": "Growth", + "env": "Staging", + "rpm": 400, + "rps": 15 + }, + { + "bucket": "kratos-public-low", + "tier": "Production", + "env": "Development", + "rpm": 400, + "rps": 15 + }, + { + "bucket": "kratos-public-low", + "tier": "Production", + "env": "Production", + "rpm": 2400, + "rps": 80 + }, + { + "bucket": "kratos-public-low", + "tier": "Production", + "env": "Staging", + "rpm": 400, + "rps": 15 + }, + { + "bucket": "kratos-public-medium", + "tier": "Developer", + "env": "Development", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-public-medium", + "tier": "Developer", + "env": "Production", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-public-medium", + "tier": "Developer", + "env": "Staging", + "rpm": 100, + "rps": 5 + }, + { + "bucket": "kratos-public-medium", + "tier": "Enterprise", + "env": "Development", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-public-medium", + "tier": "Enterprise", + "env": "Production", + "rpm": 1600, + "rps": 55 + }, + { + "bucket": "kratos-public-medium", + "tier": "Enterprise", + "env": "Staging", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-public-medium", + "tier": "Growth", + "env": "Development", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-public-medium", + "tier": "Growth", + "env": "Production", + "rpm": 800, + "rps": 30 + }, + { + "bucket": "kratos-public-medium", + "tier": "Growth", + "env": "Staging", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-public-medium", + "tier": "Production", + "env": "Development", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "kratos-public-medium", + "tier": "Production", + "env": "Production", + "rpm": 400, + "rps": 15 + }, + { + "bucket": "kratos-public-medium", + "tier": "Production", + "env": "Staging", + "rpm": 200, + "rps": 10 + }, + { + "bucket": "polis-public-low", + "tier": "Developer", + "env": "Development", + "rpm": 15, + "rps": 2 + }, + { + "bucket": "polis-public-low", + "tier": "Developer", + "env": "Production", + "rpm": 15, + "rps": 2 + }, + { + "bucket": "polis-public-low", + "tier": "Developer", + "env": "Staging", + "rpm": 15, + "rps": 2 + }, + { + "bucket": "polis-public-low", + "tier": "Enterprise", + "env": "Development", + "rpm": 30, + "rps": 2 + }, + { + "bucket": "polis-public-low", + "tier": "Enterprise", + "env": "Production", + "rpm": 250, + "rps": 10 + }, + { + "bucket": "polis-public-low", + "tier": "Enterprise", + "env": "Staging", + "rpm": 30, + "rps": 2 + }, + { + "bucket": "polis-public-low", + "tier": "Growth", + "env": "Development", + "rpm": 30, + "rps": 2 + }, + { + "bucket": "polis-public-low", + "tier": "Growth", + "env": "Production", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "polis-public-low", + "tier": "Growth", + "env": "Staging", + "rpm": 30, + "rps": 2 + }, + { + "bucket": "polis-public-low", + "tier": "Production", + "env": "Development", + "rpm": 30, + "rps": 2 + }, + { + "bucket": "polis-public-low", + "tier": "Production", + "env": "Production", + "rpm": 60, + "rps": 3 + }, + { + "bucket": "polis-public-low", + "tier": "Production", + "env": "Staging", + "rpm": 30, + "rps": 2 + }, + { + "bucket": "polis-public-medium", + "tier": "Developer", + "env": "Development", + "rpm": 60, + "rps": 3 + }, + { + "bucket": "polis-public-medium", + "tier": "Developer", + "env": "Production", + "rpm": 60, + "rps": 3 + }, + { + "bucket": "polis-public-medium", + "tier": "Developer", + "env": "Staging", + "rpm": 60, + "rps": 3 + }, + { + "bucket": "polis-public-medium", + "tier": "Enterprise", + "env": "Development", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "polis-public-medium", + "tier": "Enterprise", + "env": "Production", + "rpm": 1000, + "rps": 35 + }, + { + "bucket": "polis-public-medium", + "tier": "Enterprise", + "env": "Staging", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "polis-public-medium", + "tier": "Growth", + "env": "Development", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "polis-public-medium", + "tier": "Growth", + "env": "Production", + "rpm": 500, + "rps": 20 + }, + { + "bucket": "polis-public-medium", + "tier": "Growth", + "env": "Staging", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "polis-public-medium", + "tier": "Production", + "env": "Development", + "rpm": 120, + "rps": 7 + }, + { + "bucket": "polis-public-medium", + "tier": "Production", + "env": "Production", + "rpm": 250, + "rps": 10 + }, + { + "bucket": "polis-public-medium", + "tier": "Production", + "env": "Staging", + "rpm": 120, + "rps": 7 + } + ] +} From 3e3fbd422a9599b9549389c6814fc1cf1252725d Mon Sep 17 00:00:00 2001 From: unatasha8 Date: Wed, 4 Mar 2026 17:25:30 -0800 Subject: [PATCH 4/7] docs: fixed formating issues --- docs/guides/rate-limits.mdx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/guides/rate-limits.mdx b/docs/guides/rate-limits.mdx index 7d975410d9..6a8ea794e1 100644 --- a/docs/guides/rate-limits.mdx +++ b/docs/guides/rate-limits.mdx @@ -4,8 +4,10 @@ title: Understand Ory Network rate limits sidebar_label: Rate limits --- -:::info Rate limit changes The way Ory calculates rate limits is changing. Customers who joined before March 1, 2026, keep their -existing rate limits. New customers are subject to the updated calculation. ::: +:::info Rate limit changes +The way Ory calculates rate limits is changing. Customers who joined before March 1, 2026, keep their +existing rate limits. New customers are subject to the updated calculation. +::: Ory uses rate limiting to protect your applications against abuse, attacks, and service disruptions, and to maintain fair resource allocation and network stability. @@ -42,9 +44,11 @@ Buckets follow a `{service}-{access}-{cost}` naming pattern. For example: - `kratos-admin-high` — expensive admin operations like `POST /admin/identities` - `hydra-public-medium` — moderate-cost endpoints like `POST /oauth2/token` -:::info A bucket counter is shared across all endpoints in the same bucket. For example, `POST /admin/relation-tuples` and  +:::info +A bucket counter is shared across all endpoints in the same bucket. For example, `POST /admin/relation-tuples` and  `DELETE /admin/relation-tuples` both belong to `keto-admin-high`, so every call to either endpoint counts against the same limit. -Plan your request volumes accordingly. ::: +Plan your request volumes accordingly. +::: ### Rate limit structure From f2d82185ba0833014532b4d41107416595d74bdb Mon Sep 17 00:00:00 2001 From: unatasha8 Date: Wed, 4 Mar 2026 17:50:09 -0800 Subject: [PATCH 5/7] docs: fix formatting --- docs/guides/rate-limits.mdx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/guides/rate-limits.mdx b/docs/guides/rate-limits.mdx index 6a8ea794e1..3758c4b371 100644 --- a/docs/guides/rate-limits.mdx +++ b/docs/guides/rate-limits.mdx @@ -4,9 +4,11 @@ title: Understand Ory Network rate limits sidebar_label: Rate limits --- -:::info Rate limit changes -The way Ory calculates rate limits is changing. Customers who joined before March 1, 2026, keep their -existing rate limits. New customers are subject to the updated calculation. +:::info + +Rate limit changes The way Ory calculates rate limits is changing. Customers who joined before March 1, 2026, keep their existing +rate limits. New customers are subject to the updated calculation. + ::: Ory uses rate limiting to protect your applications against abuse, attacks, and service disruptions, and to maintain fair resource @@ -44,10 +46,12 @@ Buckets follow a `{service}-{access}-{cost}` naming pattern. For example: - `kratos-admin-high` — expensive admin operations like `POST /admin/identities` - `hydra-public-medium` — moderate-cost endpoints like `POST /oauth2/token` -:::info +:::info + A bucket counter is shared across all endpoints in the same bucket. For example, `POST /admin/relation-tuples` and  `DELETE /admin/relation-tuples` both belong to `keto-admin-high`, so every call to either endpoint counts against the same limit. -Plan your request volumes accordingly. +Plan your request volumes accordingly. + ::: ### Rate limit structure From 0b45fcdeb9ee73d8fea502d2eb48deaf7b7c0505 Mon Sep 17 00:00:00 2001 From: Wassim Bougarfa <12980387+wassimoo@users.noreply.github.com> Date: Thu, 5 Mar 2026 16:01:59 +0100 Subject: [PATCH 6/7] docs: update terminology in RateLimitsTable component --- src/components/RateLimitsTable/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/RateLimitsTable/index.tsx b/src/components/RateLimitsTable/index.tsx index 9f16e37ef2..b644447398 100644 --- a/src/components/RateLimitsTable/index.tsx +++ b/src/components/RateLimitsTable/index.tsx @@ -178,7 +178,7 @@ export default function RateLimitsTable({

- Thresholds by bucket ({tier} / {env}) + Thresholds per bucket ({tier} / {env}) {searchQuery && ( (filtered by search) From 8b8c25800df672c986559ea19f4abe7e20ac9716 Mon Sep 17 00:00:00 2001 From: unatasha8 Date: Thu, 5 Mar 2026 13:49:43 -0800 Subject: [PATCH 7/7] docs: added old rate limit page back, broke up new rate limit pages into mulit pages --- docs/guides/load-performance-testing.mdx | 11 + docs/guides/rate-limit-endpoint.mdx | 59 +++++ docs/guides/rate-limits-new.mdx | 44 ++++ docs/guides/rate-limits-project.mdx | 98 ++++++++ docs/guides/rate-limits.mdx | 285 ++++++++++++++--------- src/sidebar.ts | 11 +- 6 files changed, 391 insertions(+), 117 deletions(-) create mode 100644 docs/guides/load-performance-testing.mdx create mode 100644 docs/guides/rate-limit-endpoint.mdx create mode 100644 docs/guides/rate-limits-new.mdx create mode 100644 docs/guides/rate-limits-project.mdx diff --git a/docs/guides/load-performance-testing.mdx b/docs/guides/load-performance-testing.mdx new file mode 100644 index 0000000000..8db2a8afef --- /dev/null +++ b/docs/guides/load-performance-testing.mdx @@ -0,0 +1,11 @@ +--- +id: load-performance-testing +title: Load and performance testing +sidebar_label: Load and performance testing +--- + +Load testing, stress testing, and performance testing against Ory Network require prior written approval. Unauthorized load +testing may be detected as abusive traffic and result in temporary blocking of your project or IP addresses. + +For eligibility, request procedures, and requirements, see the +[Load Testing Policy](https://www.ory.sh/legal/load-testing-policy). diff --git a/docs/guides/rate-limit-endpoint.mdx b/docs/guides/rate-limit-endpoint.mdx new file mode 100644 index 0000000000..14f9b5575b --- /dev/null +++ b/docs/guides/rate-limit-endpoint.mdx @@ -0,0 +1,59 @@ +--- +id: rate-limits-endpoint +title: Endpoint rate limits for Ory Network +sidebar_label: Endpoint rate limits +--- + +Endpoint-based rate limits apply to individual API endpoints regardless of your project rate limits. They protect specific +endpoints against brute-force and credential stuffing attacks, which typically originate from a limited set of IP addresses or JA4 +fingerprints. + +Benefits: + +- Enhanced security: Restricts requests from specific sources, making attacks significantly harder to succeed +- Bot protection: Differentiates genuine users from harmful automated activity +- Granular control: Fine-tunes security for individual endpoints without compromising user experience + +## Types of endpoint-based protection + +Ory implements two layers of endpoint-based protection: + +- Volumetric: Limits the total amount of traffic over time. +- Inflight: Limits the number of concurrent active requests. + +### Volumetric rate limits + +Volumetric rate limits analyze incoming request patterns based on: + +- Source identification: IP addresses and JA3/JA4 fingerprints +- Request frequency: Detects volumetric attacks and system overwhelm attempts +- Authentication status: Different limits for authenticated vs. unauthenticated requests +- HTTP method: Varying limits based on GET, POST, etc. + +### Inflight rate limits + +Inflight rate limits protect critical endpoints from concurrent request attacks. By preventing multiple requests to the same +resource at once, they eliminate race conditions, ensure data consistency, and let critical operations complete safely. + +The following endpoints are protected by rate limits. + +| Type | Endpoint | HTTP Methods | Ratelimit Key | Action: enforced vs report-only | +| :------- | :------------------------------------------ | :----------------------- | :----------------------------------------------- | :------------------------------------- | +| Inflight | `/admin/identities` | `POST`, `PATCH` | `{project_id} + {full_path}` | Blocks concurrent requests (enforced) | +| Inflight | `/admin/identities/{id}` | `PUT`, `PATCH`, `DELETE` | `{project_id} + {full_path}` | Blocks concurrent requests (enforced) | +| Inflight | `/admin/identities/{id}/credentials/{type}` | `DELETE` | `{project_id} + {full_path}` | Blocks concurrent requests (enforced) | +| Inflight | `/admin/identities/{id}/sessions` | `DELETE` | `{project_id} + {full_path}` | Blocks concurrent requests (enforced) | +| Inflight | `/admin/sessions/{id}` | `DELETE` | `{project_id} + {full_path}` | Logs concurrent requests (report-only) | +| Inflight | `/admin/sessions/{id}/extend` | `PATCH` | `{project_id} + {full_path}` | Logs concurrent requests (report-only) | +| Inflight | `/self-service/recovery` | `POST` | `{project_id} + {path} + "/" + {email\|flow_id}` | Logs concurrent requests (report-only) | + +:::note + +Enforced-endpoints return HTTP 429 when the rate limit is exceeded. Report-only-endpoints currently only log rate limit +violations; they don't block requests. GET, OPTIONS, and HEAD requests are exempt from rate limiting. + +::: + +### Configuration and rule management + +The endpoint-based rate limit rules are set and managed by Ory. These rules aren't directly configurable by customers. diff --git a/docs/guides/rate-limits-new.mdx b/docs/guides/rate-limits-new.mdx new file mode 100644 index 0000000000..0c19dce5f4 --- /dev/null +++ b/docs/guides/rate-limits-new.mdx @@ -0,0 +1,44 @@ +--- +id: rate-limits-new +title: New Ory Network rate limits +sidebar_label: New rate limits +--- + +:::info + +!! ADD COMMUNICATION NOTICE !! + +::: + +Ory uses rate limits to protect your applications against abuse, attacks, and service disruptions, and to maintain fair resource +allocation and network stability. + +## Types of rate limits + +Ory uses two types of rate limits: + +- [Project rate limits](./rate-limits-project): Control the overall request volume your projects can make to Ory APIs, based on + your subscription tier and project environment. +- [Endpoint-based rate limits](./rate-limits-endpoint): Control traffic to individual endpoints to protect against volumetric + attacks, brute-force attempts, and concurrent request abuse—regardless of your project rate limits. + +## Identify the rate limits that apply to your project + +In the **Project rate limit table** below: + +1. Select your subscription tier from the **Tier** dropdown. Options are Developer, Production, Growth, or Enterprise. +2. Select your project environment from the **Environment** dropdown. Options are Production, Staging, or Development. +3. To search by API path, enter the API path into the **Search API path** box. The endpoint appears highlighted. Look to see which + bucket it belongs to for its rate limit. + +:::info + +Project rate limits use a bucket system to group endpoints and apply thresholds. Understanding how buckets work will help you +understand the project rate limit table below. See [Project rate limits](./rate-limits-project) to learn how rate limits are +applied per bucket. + +::: + +### Project rate limit table + + diff --git a/docs/guides/rate-limits-project.mdx b/docs/guides/rate-limits-project.mdx new file mode 100644 index 0000000000..345abbe41a --- /dev/null +++ b/docs/guides/rate-limits-project.mdx @@ -0,0 +1,98 @@ +--- +id: rate-limits-project +title: Project rate limits for Ory Network +sidebar_label: Project rate limits +--- + +Each project has a set of rate limit buckets. A bucket is a named group of API endpoints that share the same rate limit +thresholds. When a request comes in, Ory resolves which bucket the endpoint belongs to and applies the threshold for that bucket. + +Bucket thresholds are determined by two factors: + +- **Subscription tier:** The project's subscription tier (Developer, Production, Growth, or Enterprise). +- **Project environment:** The project's environment (Production, Staging, or Development). + +For a detailed explanation of tiers and environments, see our [Workspaces and environments guide](/docs/guides/workspaces). + +## Rate limits per bucket + +Buckets follow a `{service}-{access}-{cost}` naming pattern. For example: + +- `kratos-public-low` — lightweight public endpoints like `GET /sessions/whoami` +- `kratos-admin-high` — expensive admin operations like `POST /admin/identities` +- `hydra-public-medium` — moderate-cost endpoints like `POST /oauth2/token` + +:::info + +A bucket counter is shared across all endpoints in the same bucket. For example, `POST /admin/relation-tuples` and  +`DELETE /admin/relation-tuples` both belong to `keto-admin-high`, so every call to either endpoint counts against the same limit. +Plan your request volumes accordingly. + +::: + +### Rate limit dimensions + +You will see two rate limits for each bucket: + +- **Burst limit**: Maximum requests per second (rps), allowing for short traffic spikes. +- **Sustained limit**: Maximum requests per minute (rpm), ensuring consistent performance over time. + +## Monitor rate limit headers + +Ory Network includes rate limit information in API response headers for project rate-limits. Use these headers to avoid exceeding +the applicable rate limit. Your client must handle these responses to maintain service quality. + +| Header | Description | +| ----------------------- | --------------------------------------------------------------------------------------- | +| `x-ratelimit-limit` | The rate limit ceiling(s) for the current request, including burst and sustained limits | +| `x-ratelimit-remaining` | Number of requests remaining in the current window | +| `x-ratelimit-reset` | Number of seconds until the rate limit window resets | + +Example header values: + +```shell +x-ratelimit-limit: 10, 10;w=1, 300;w=60 +x-ratelimit-remaining: 8 +x-ratelimit-reset: 1 +``` + +The `x-ratelimit-limit` header follows the +[IETF RateLimit header fields draft](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/), where `w=1` +indicates a 1-second window and `w=60` indicates a 60-second window. Use these headers to throttle requests proactively and reduce +the likelihood of hitting 429 errors. + +## How to handle 429 responses + +When your client receives a `429 Too Many Requests` response, you've exceeded the applicable rate limit. Your client must handle +these responses to maintain service quality. + +Your implementation must: + +- **Detect 429 responses**: Monitor for HTTP 429 status codes on all API calls. +- **Implement exponential backoff**: When receiving a 429, pause and retry with increasing delays (for example: 1s, 2s, 4s, 8s). +- **Respect rate limit headers**: Check `x-ratelimit-remaining` and `x-ratelimit-reset`, when available, to throttle requests + proactively. +- **Avoid retry storms**: Don't retry failed requests in a tight loop. + +### Exponential backoff strategy + +Implement an exponential backoff strategy to proactively avoid hitting rate limits. + +```jsx +async function callApiWithBackoff(request, maxRetries = 5) { + for (let attempt = 0; attempt < maxRetries; attempt++) { + const response = await fetch(request) + if (response.status === 429) { + const delay = Math.pow(2, attempt) * 1000 // 1s, 2s, 4s, 8s, 16s + await new Promise((resolve) => setTimeout(resolve, delay)) + continue + } + return response + } + throw new Error("Max retries exceeded") +} +``` + +Clients that repeatedly exceed rate limits without proper backoff may have their API access temporarily blocked. For high-volume +use cases that exceed your plan's limits, open a support ticket via the [Ory Console](https://console.ory.sh/support) or email +[support@ory.sh](mailto:support@ory.sh). diff --git a/docs/guides/rate-limits.mdx b/docs/guides/rate-limits.mdx index 3758c4b371..cf23e1aefc 100644 --- a/docs/guides/rate-limits.mdx +++ b/docs/guides/rate-limits.mdx @@ -1,110 +1,195 @@ --- id: rate-limits -title: Understand Ory Network rate limits +title: Understand Ory Network rate limiting sidebar_label: Rate limits --- :::info -Rate limit changes The way Ory calculates rate limits is changing. Customers who joined before March 1, 2026, keep their existing -rate limits. New customers are subject to the updated calculation. +!! ADD COMMUNICATION NOTICE !! ::: -Ory uses rate limiting to protect your applications against abuse, attacks, and service disruptions, and to maintain fair resource -allocation and network stability. +This page provides a high-level overview of the rate limiting mechanisms employed by Ory to ensure system security and +availability. Rate limiting protects your applications against abuse and attacks, prevents service disruptions, and ensures fair +usage for all our customers. ## Types of rate limits -Ory uses two types of rate limits: +Ory implements two main rate limit types: -- [Project rate limits](#project-rate-limits): Control the overall request volume your projects can make to Ory APIs, based on - your subscription tier and project environment. -- [Endpoint-based rate limits](#endpoint-based-rate-limits): Control traffic to individual endpoints to protect against volumetric - attacks, brute-force attempts, and concurrent request abuse—regardless of your project rate limits. +1. Project rate limits: Based on your subscription plan and environment (Production, Staging, or Development). These control the + overall request volume your projects can make to Ory's APIs. +2. Endpoint-based rate limits: Additional security controls that protect specific endpoints against attacks like brute-force, + credential stuffing, and concurrent request abuse, regardless of your project limits. -Project rate limits use a bucket system to group endpoints and apply thresholds. Understanding how buckets work will help you -interpret the project rate limit table below. +## Project rate limits in workspaces -## Project rate limits +With the introduction of workspaces in Ory Network, rate limits are now applied to projects based on their assigned environment +and the workspace's subscription plan. This approach ensures fair resource allocation and maintains the stability of the Ory +Network across different usage scenarios. -Each project has a set of rate limit buckets. A bucket is a named group of API endpoints that share the same rate limit -thresholds. When a request comes in, Ory resolves which bucket the endpoint belongs to and applies the threshold for that bucket. +### How project rate limits work in workspaces -Bucket thresholds are determined by two factors: +Rate limits for each project are determined by two main factors: -- **Subscription tier:** The project's subscription tier (Developer, Production, Growth, or Enterprise). -- **Project environment:** The project's environment (Production, Staging, or Development). +1. Workspace subscription: Your subscription plan (Developer, Production, Growth, or Enterprise) sets the baseline for your rate + limits. +2. Project environment: Within each workspace, projects can be assigned to Production, Staging, or Development environments, each + with specific rate limit configurations. -For a detailed explanation of tiers and environments, see our [Workspaces and environments guide](/docs/guides/workspaces). +For a detailed explanation of workspaces and environments, see our [Workspaces and environments guide](/docs/guides/workspaces). -### Bucket naming +### Rate limit structure -Buckets follow a `{service}-{access}-{cost}` naming pattern. For example: +Each rate limit policy includes two limits: -- `kratos-public-low` — lightweight public endpoints like `GET /sessions/whoami` -- `kratos-admin-high` — expensive admin operations like `POST /admin/identities` -- `hydra-public-medium` — moderate-cost endpoints like `POST /oauth2/token` +1. Burst limit: Maximum requests per second (rps), allowing for short traffic spikes. +2. Sustained limit: Maximum requests per minute (rpm), ensuring consistent performance over time. -:::info +### Determine your project's rate limits -A bucket counter is shared across all endpoints in the same bucket. For example, `POST /admin/relation-tuples` and  -`DELETE /admin/relation-tuples` both belong to `keto-admin-high`, so every call to either endpoint counts against the same limit. -Plan your request volumes accordingly. +To identify the rate limits that apply to your project: -::: +1. Check your workspace subscription plan (Developer, Production, Growth, or Enterprise). +2. Identify the environment (Production, Staging, or Development) assigned to your project. +3. Refer to the tables below based on your subscription plan and project environment. -### Rate limit structure +### Rate limit tables by subscription plan -You will see two rate limits for each bucket: +#### Developer plan rate limits -1. Burst limit: Maximum requests per second (rps), allowing for short traffic spikes. -2. Sustained limit: Maximum requests per minute (rpm), ensuring consistent performance over time. +| Environment | Path / Bucket | Burst (rps) | Sustained (rpm) | +| :---------- | :-------------------------------- | ----------: | --------------: | +| Development | `/sessions/whoami` | 10 | 300 | +| | `/admin/oauth2/introspect` | 10 | 300 | +| | `/relation-tuples/check` | 10 | 300 | +| | `GET /admin/identities` | 1 | 10 | +| | `POST /admin/identities` | 1 | 10 | +| | `PATCH /admin/identities` | 1 | 10 | +| | `POST /admin/recovery/*` | 1 | 10 | +| | `POST /self-service/registration` | 1 | 10 | +| | `POST /self-service/recovery` | 1 | 10 | +| | `POST /self-service/settings` | 1 | 10 | +| | `POST /self-service/verification` | 1 | 10 | +| | `/scim/**` | 1 | 10 | +| | `*` | 5 | 150 | -### Monitor rate limit headers +:::note -Ory Network includes rate limit information in API response headers for project rate-limits. Use these headers to avoid exceeding -the applicable rate limit. Your client must handle these responses to maintain service quality. +For Developer plans, all environments (Production, Staging, Development) use the same rate limits. -| Header | Description | -| ----------------------- | --------------------------------------------------------------------------------------- | -| `x-ratelimit-limit` | The rate limit ceiling(s) for the current request, including burst and sustained limits | -| `x-ratelimit-remaining` | Number of requests remaining in the current window | -| `x-ratelimit-reset` | Number of seconds until the rate limit window resets | +::: -Example header values: +#### Production plan rate limits + +| Environment | Path / Bucket | Burst (rps) | Sustained (rpm) | +| :-------------------- | :-------------------------------- | ----------: | --------------: | +| Production | `/sessions/whoami` | 80 | 1800 | +| | `/admin/oauth2/introspect` | 80 | 1800 | +| | `/relation-tuples/check` | 80 | 1800 | +| | `GET /admin/identities` | 10 | 300 | +| | `POST /admin/recovery/*` | 10 | 30 | +| | `/scim/**` | 10 | 300 | +| | `*` | 40 | 900 | +| Development / Staging | `/sessions/whoami` | 10 | 300 | +| | `/admin/oauth2/introspect` | 10 | 300 | +| | `/relation-tuples/check` | 10 | 300 | +| | `GET /admin/identities` | 1 | 10 | +| | `POST /admin/identities` | 1 | 10 | +| | `PATCH /admin/identities` | 1 | 10 | +| | `POST /admin/recovery/*` | 1 | 10 | +| | `POST /self-service/registration` | 1 | 10 | +| | `POST /self-service/recovery` | 1 | 10 | +| | `POST /self-service/settings` | 1 | 10 | +| | `POST /self-service/verification` | 1 | 10 | +| | `/scim/**` | 1 | 10 | +| | `*` | 5 | 150 | + +:::note + +Production plan rate limits also apply to the Legacy `Essential` plan. -```shell -x-ratelimit-limit: 10, 10;w=1, 300;w=60 -x-ratelimit-remaining: 8 -x-ratelimit-reset: 1 -``` +::: -The `x-ratelimit-limit` header follows the -[IETF RateLimit header fields draft](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/), where `w=1` -indicates a 1-second window and `w=60` indicates a 60-second window. Use these headers to throttle requests proactively and reduce -the likelihood of hitting 429 errors. +#### Growth plan rate limits + +| Environment | Path / Bucket | Burst (rps) | Sustained (rpm) | +| :-------------------- | :-------------------------------- | ----------: | --------------: | +| Production | `/sessions/whoami` | 800 | 18000 | +| | `/admin/oauth2/introspect` | 800 | 18000 | +| | `/relation-tuples/check` | 800 | 18000 | +| | `GET /admin/identities` | 20 | 600 | +| | `POST /admin/recovery/*` | 10 | 300 | +| | `/scim/**` | 10 | 300 | +| | `*` | 400 | 9000 | +| Development / Staging | `/sessions/whoami` | 10 | 300 | +| | `/admin/oauth2/introspect` | 10 | 300 | +| | `/relation-tuples/check` | 10 | 300 | +| | `GET /admin/identities` | 1 | 10 | +| | `POST /admin/identities` | 1 | 10 | +| | `PATCH /admin/identities` | 1 | 10 | +| | `POST /admin/recovery/*` | 1 | 10 | +| | `POST /self-service/registration` | 1 | 10 | +| | `POST /self-service/recovery` | 1 | 10 | +| | `POST /self-service/settings` | 1 | 10 | +| | `POST /self-service/verification` | 1 | 10 | +| | `/scim/**` | 1 | 10 | +| | `*` | 5 | 150 | + +:::note + +Growth plan rate limits also apply to the legacy `Scale` plan. -See [How to handle 429 responses](#how-to-handle-429-responses) for an example of how to deal with potential 429 responses. +::: -## Calculate the rate limits that apply to your project +#### Enterprise plan rate limits + +The Enterprise plan has the same default rate limits as the Growth plan. If your use case requires higher limits, +[get in touch with us to discuss your requirements](https://ory.com/contact). + +| Environment | Path / Bucket | Burst (rps) | Sustained (rpm) | +| :-------------------- | :-------------------------------- | ----------: | --------------: | +| Production | `/sessions/whoami` | 1200 | 36000 | +| | `/admin/oauth2/introspect` | 1200 | 36000 | +| | `/relation-tuples/check` | 1200 | 36000 | +| | `GET /admin/identities` | 60 | 1200 | +| | `POST /admin/recovery/*` | 20 | 600 | +| | `/scim/**` | 20 | 600 | +| | `*` | 800 | 18000 | +| Development / Staging | `/sessions/whoami` | 10 | 300 | +| | `/admin/oauth2/introspect` | 10 | 300 | +| | `/relation-tuples/check` | 10 | 300 | +| | `GET /admin/identities` | 1 | 10 | +| | `POST /admin/identities` | 1 | 10 | +| | `PATCH /admin/identities` | 1 | 10 | +| | `POST /admin/recovery/*` | 1 | 10 | +| | `POST /self-service/registration` | 1 | 10 | +| | `POST /self-service/recovery` | 1 | 10 | +| | `POST /self-service/settings` | 1 | 10 | +| | `POST /self-service/verification` | 1 | 10 | +| | `/scim/**` | 1 | 10 | +| | `*` | 5 | 150 | -In the **Project rate limit table** below: +## Endpoint-based rate limits -1. Select your subscription tier from the **Tier** dropdown. Options are Developer, Production, Growth, or Enterprise. -2. Select your project environment from the **Environment** dropdown. Options are Production, Staging, or Development. -3. To search by API path, enter the API path into the **Search API path** box. The endpoint appears highlighted. Look to see which - bucket it belongs to for its rate limit. +Endpoint-based rate limits are controls applied to individual API endpoints within your Ory projects. Unlike project rate limits, +which govern overall project request volumes, endpoint-based rate limits focus on safeguarding specific functionalities against +abuse. -### Project rate limit table +:::note - +Endpoint-based rate limits operate independently from project rate limits in workspaces. While project rate limits control overall +request volumes based on your subscription and environment, endpoint-based rate limits provide additional security for specific +endpoints regardless of your project rate limit values. -## Endpoint-based rate limits +::: + +### Purpose of endpoint-based rate limits -Endpoint-based rate limits apply to individual API endpoints regardless of your project rate limits. They protect specific -endpoints against brute-force and credential stuffing attacks, which typically originate from a limited set of IP addresses or JA4 -fingerprints. +Endpoint-based rate limits protect individual endpoints against common attack vectors like brute-force and credential stuffing. +These attacks typically involve numerous attempts to guess credentials or exploit vulnerabilities, often from a limited set of IP +addresses or JA4 fingerprints. Benefits: @@ -118,7 +203,7 @@ Ory implements two layers of endpoint-based protection: #### Volumetric rate limits -Volumetric rate limits analyze incoming request patterns based on: +Analyzes incoming request patterns based on: - Source identification: IP addresses and JA3/JA4 fingerprints - Request frequency: Detects volumetric attacks and system overwhelm attempts @@ -128,13 +213,20 @@ Volumetric rate limits analyze incoming request patterns based on: #### Inflight rate limits Inflight rate limits protect critical endpoints from concurrent request attacks. By preventing multiple requests to the same -resource at once, they eliminate race conditions, ensure data consistency, and let critical operations complete safely. +resource at once, it eliminates race conditions, ensures data consistency, and lets critical operations complete safely. + +:::note + +These limits mainly protect against write requests to the same resource happening in parallel — usually caused by implementation +issues. + +::: ### Protected endpoints -The following endpoints are protected by volumetric or inflight rate limits. +The following endpoints are protected by different types of rate limiting: -| Type | Endpoint | HTTP Methods | Ratelimit Key | Action: enforced vs report-only | +| Type | Endpoint | HTTP Methods | Ratelimit Key | Action | | :--------- | :------------------------------------------ | :----------------------- | :----------------------------------------------- | :------------------------------------- | | Volumetric | | | | To be added later | | Inflight | `/admin/identities` | `POST`, `PATCH` | `{project_id} + {full_path}` | Blocks concurrent requests (enforced) | @@ -145,56 +237,17 @@ The following endpoints are protected by volumetric or inflight rate limits. | Inflight | `/admin/sessions/{id}/extend` | `PATCH` | `{project_id} + {full_path}` | Logs concurrent requests (report-only) | | Inflight | `/self-service/recovery` | `POST` | `{project_id} + {path} + "/" + {email\|flow_id}` | Logs concurrent requests (report-only) | -:::note Enforced-endpoints return HTTP 429 when the rate limit is exceeded. Report-only-endpoints currently only log rate limit -violations; they don't block requests. GET, OPTIONS, and HEAD requests are exempt from rate limiting. ::: - -### Configuration and rule management - -The endpoint-based rate limit rules are set and managed by Ory. These rules aren't directly configurable by customers. - -## How to handle 429 responses +:::note -When your client receives a `429 Too Many Requests` response, you've exceeded the applicable rate limit. Your client must handle -these responses to maintain service quality. +Report-only endpoints are observed over a period of time before enforcement is enabled. They currently log rate limit violations +for monitoring purposes but don't block requests, while enforced endpoints return HTTP 429 when rate limits are exceeded. GET, +OPTIONS, and HEAD requests are exempt from rate limiting. -Your implementation must: - -- **Detect 429 responses**: Monitor for HTTP 429 status codes on all API calls. -- **Implement exponential backoff**: When receiving a 429, pause and retry with increasing delays (for example: 1s, 2s, 4s, 8s). -- **Respect rate limit headers**: Check `x-ratelimit-remaining` and `x-ratelimit-reset`, when available, to throttle requests - proactively. -- **Avoid retry storms**: Don't retry failed requests in a tight loop. - -### Exponential backoff strategy - -Implement an exponential backoff strategy to proactively avoid hitting rate limits. - -```jsx -async function callApiWithBackoff(request, maxRetries = 5) { - for (let attempt = 0; attempt < maxRetries; attempt++) { - const response = await fetch(request) - if (response.status === 429) { - const delay = Math.pow(2, attempt) * 1000 // 1s, 2s, 4s, 8s, 16s - await new Promise((resolve) => setTimeout(resolve, delay)) - continue - } - return response - } - throw new Error("Max retries exceeded") -} -``` - -See [Monitor rate limit headers](#monitor-rate-limit-headers) for information about how to monitor rate limit headers and throttle -requests proactively. - -Clients that repeatedly exceed rate limits without proper backoff may have their API access temporarily blocked. For high-volume -use cases that exceed your plan's limits, open a support ticket via the [Ory Console](https://console.ory.sh/support) or email -[support@ory.sh](mailto:support@ory.sh). +::: -## Load and performance testing +### Configuration and management -Load testing, stress testing, and performance testing against Ory Network require prior written approval. Unauthorized load -testing may be detected as abusive traffic and result in temporary blocking of your project or IP addresses. +#### Rule management -For eligibility, request procedures, and requirements, see the -[Load Testing Policy](https://www.ory.sh/legal/load-testing-policy). +The endpoint-based rate limit rules are set and managed by Ory. These rules aren't directly configurable by Enterprise and Growth +customers yet. diff --git a/src/sidebar.ts b/src/sidebar.ts index d934da6619..7813d98c3d 100644 --- a/src/sidebar.ts +++ b/src/sidebar.ts @@ -74,7 +74,6 @@ const oidcSSO: SidebarItemConfig = { const api: SidebarItemsConfig = [ homeLink, "reference/api", - "ecosystem/api-design", { type: "category", @@ -90,6 +89,16 @@ const api: SidebarItemsConfig = [ "guides/cors", "guides/api-rest-pagination", "guides/rate-limits", + { + type: "category", + label: "Rate limits NEW!", + link: { + type: "doc", + id: "guides/rate-limits-new", + }, + items: ["guides/rate-limits-project", "guides/rate-limits-endpoint"], + }, + "guides/load-performance-testing", "guides/ip-allowlist", "api/eventual-consistency", "kratos/reference/jsonnet",