Synq Docs
Reference

Rate limits

Every limit Synq counts requests against, and how many it allows in what window.

Synq counts requests against these limits, per rule. A request over one answers 429 with a Retry-After header in seconds: the management API and the account API with the code rate_limited, the protocol endpoints with OAuth's too_many_requests, and the hosted pages with a page that says how long to wait. Wait that long, then try again; never retry in a loop.

RuleAllowedWindowWhat it counts
authorize.ip601 minuteAuthorization requests from one address.
interaction.ip601 minuteSign-in pages and steps from one address.
signin.identifier1015 minutesSign-in attempts on one identifier (an email, a wallet address), from anywhere: what stops guessing one account's password from many addresses.
reset.identifier51 hourPassword reset requests for one address at one brand, counted apart from sign-in tries, so asking for resets can't lock anyone's sign-in.
federation.ip601 minuteUpstream providers' callbacks on the auth host from one address: each that names a flow costs a request to the provider.
token_gate.recheck1015 minutes"Check again" on the token gate page for one user at one brand: each reads the chain afresh, past what was kept.
token_gate.reads12001 minuteReads of the chain for one brand's token gates, past what was kept: spent, its gates answer that they couldn't check, so one tenant's sign-ins can't spend Synq's Helius key for every other.
token_gate.dry_runs301 minuteDry runs of a token gate or a draft rule by one org (, POST /v1/orgs/{org}/token-gates/check): each may read the chain.
token_gate.org_reads3001 minuteReads of the chain for one org's dry runs, past what was kept: their own budget, never a brand's sign-ins'.
siws.ip301 minuteWallet sign-in requests an app's own pages ask for, from one address: each is a row until it is spent or expires.
token.ip3001 minuteToken requests from one address for a public app, or an app that says nothing of itself: a confidential app's count per app instead (token.client), so a backend-for-frontend's users never share its server's address.
token.client6001 minuteToken requests from one confidential app, by the client_id it authenticates as.
par.client6001 minutePushed authorization requests from one confidential app (/request), as token.client.
client_auth.ip301 minuteFailed app authentications from one address, at the token endpoint, /request and /authorize-challenge, checked in front of all three: what stops a caller who forges credentials from leaving the per-address limits behind.
challenge.ip601 minuteOwn-UI sign-in requests at /authorize-challenge from one address: a public app's caller, or the person a confidential app's server says it signs in (Synq-End-User-IP), counted for that app alone.
challenge.client12001 minuteOwn-UI sign-in requests from one app.
introspection.client12001 minuteIntrospection by one app or API.
api_keys.client12001 minuteChecks of users' API keys by one API's own app (, POST /api-keys/verify).
revocation.client1201 minuteRevocation by one app.
protocol.ip3001 minuteUserinfo, introspection, revocation and sign-out from one address.
registration.ip101 hourApps registering themselves from one address: a few an hour.
device.poll15 secondsPolls of one device code at the token endpoint: one per interval, else slow_down.
management.ip6001 minuteManagement API requests from one address, before the caller is known: all but the calls Synq's own dashboard makes for a signed-in person, which come from one address for everyone using it. The staff API counts its own the same way, for the staff admin.
management.principal6001 minuteManagement API requests from one API key or Synq user, whatever app they call through.
management.connections101 minuteAn org's own apps at the sign-in providers, set: each asks the provider whether it takes the app, so nobody tries secrets at a provider through Synq.
custom_domain.org1024 hoursCustom domains an org adds: each one costs a slot in Cloudflare once proven, so nobody churns hostnames through Synq.
custom_domain.check11 minute"Check now" on one custom domain: each reads its DNS and Cloudflare.
mail.recipient501 hourEmail to one address, whoever sends it: nobody floods an inbox through Synq, however many orgs or brands they use (mail/limits.ts). A ceiling well above any one tenant's, so a stranger asking one brand for codes can't stop the address's email from every other.
mail.tenant_recipient101 hourEmail to one address from one org or one brand: what anyone asking one tenant can use up.
mail.ip301 hourSign-in email one client address asks for: codes to many addresses from one place. Counted by the address's /64 for IPv6.
mail.org1001 hourAn org's invitations.
mail.brand10001 hourA brand's sign-in email: codes, links, verification and resets.
mail.reply_to524 hoursConfirmations of one brand's reply-to address: each emails an address the tenant typed, so a tenant can't mail strangers through it.
email_domain.org1024 hoursSending domains one org adds: each is registered with Postmark, and a name held is a name no other org can take.
email_domain.check11 minute"Check now" on one sending domain.
mail.sender_test51 hourTests of a brand's email one person sends themselves.
reply_to_confirm.ip301 minuteThe reply-to confirmation page and its button from one address.
files.org601 hourUploads one org starts (, files/): each is a signed PUT into Synq's storage and a decode at finalize, so no tenant fills the bucket or keeps the API decoding images.