Limits
Every limit we enforce, from request rates and lockouts to lifetimes, sizes and retention, and what you get back when you reach one.
On this page
These are the limits we enforce. Values marked contract are part of the product's rules and hold on every deployment. The others protect the service and can be configured.
Too many requests get 429 rate_limited. Too many wrong codes or STKs get 423. Both come with Retry-After and details.retry_after_seconds, in seconds: wait that long, then try again.
curl -s "$ACCOUNTS_URL/v1/ids/available?id=c:probe" # the 121st check in one minute from one IP:{
"error": {
"code": "rate_limited",
"message": "Too many id availability checks from this network: the limit is 120 per minute.",
"hint": "Wait 57 seconds before trying again.",
"details": { "retry_after_seconds": 57 }
}
}Rate limits are fixed windows counted in the database, so they hold across every server. "Per
IP" means the client's address (the right-most X-Forwarded-For entry behind the load balancer).
Everything behind one address shares one budget, so a fleet of runners behind one address should
sign in once per job and reuse the session, not sign in once per command.
Rate limits
| What | Limit | Counted per |
|---|---|---|
| Verification codes sent to one email or phone (sign-in, CLI, adding an address, requirements) | 10 per 10 minutes (contract) | address |
| Verification codes sent from one network | 30 per 10 minutes | IP |
Adding an email or phone (POST /v1/me/emails, /phones), counted before any refusal | 20 per 10 minutes; 30 per 10 minutes | account; IP |
Hosted sign-in flows started (POST /v1/flows) | 300 per minute | IP |
CLI code sign-ins started (POST /v1/cli/login/start) | 60 per 10 minutes | IP |
Device sign-ins started (POST /v1/device/authorize) | 60 per 10 minutes; 600 per 10 minutes for one app's tools | IP; app |
Device codes looked up, approved or denied (/v1/device/{user_code}…) | 60 per 10 minutes | Carbon |
Connecting Google or Apple (POST /v1/me/identities/{provider}) | 30 per hour | account |
Silicon sign-in attempts (POST /v1/silicons/login) | 60 per minute | IP |
Token exchanges with an outside OIDC token (grant_type=…:token-exchange) | 60 per minute | IP |
Identity tokens (POST /v1/me/identity-tokens) | 60 per minute | Silicon |
Silicon self-creations (POST /v1/silicons) | 10 successful per hour, and 60 attempts of any outcome per hour | IP |
| Self-created Silicons waiting for one custodian | 20 pending | c:id or email |
| Transfer requests | 30 per hour | custodian |
| Silicon webhook test pings | 10 per hour | Silicon |
Id availability checks (GET /v1/ids/available) | 120 per minute | IP |
Account lookups (/v1/accounts/{uuid} and /by-id/{id} together) | 600 per minute | app or account |
| Id changes (own, or a custodian's for its Silicon; reclaims included) | 5 per rolling 24 hours | account |
| Photo uploads | 20 per hour; 20 per hour | account; sign-up |
| Imports | 60 requests per hour (dry runs and refused files count); 2,000,000 rows per 24 hours | app |
Bug reports (POST /v1/reports) | 5 per hour | IP |
Telemetry (POST /v1/telemetry/events) | 120 requests per minute | IP |
Lockouts
| What | Lock |
|---|---|
| 10 wrong verification codes in a row for one address (any flow, the CLI, the account site) | every code to that address is refused for 60 seconds (contract: 1 minute): 423 verification_locked. A right code ends the streak; a resend keeps it |
| 10 wrong STKs in a row for one Silicon | its sign-in is refused for 60 seconds: 423 login_locked |
Lifetimes
| What | Lifetime |
|---|---|
| Verification code (6 digits) | 10 minutes (contract); a resend replaces it. resend_available_at suggests waiting 30 seconds |
Hosted sign-in flow (and its sa_flow cookie) | 60 minutes |
Sign-up session (sa_signup) | 48 hours (contract) |
Browser session (sa_session) | 900 days |
| Access token | 30 minutes, 1800 seconds (contract) |
| Refresh token / sign-in | 900 days from the sign-in, not extended by refreshing (contract); every refresh rotates the token |
| Authorization code | 120 seconds, single use |
Short-lived token (slt_…) | 120 seconds, single use, one app |
| Sign-in from a trusted outside token (token exchange) | until the outside token expires: at least 30 minutes, at most 12 hours; refresh tokens rotate within it |
| Identity token | 60 to 3600 seconds, default 300 |
| A trusted issuer's keys (JWKS) | cached for 10 minutes; fetched again for an unknown kid, at most every 30 seconds per issuer |
| Device code | 600 seconds; poll every 5 seconds (slow_down if faster) |
| Silicon custodian request (initial or transfer) | 14 days (contract: 2 weeks) |
| Id reservation after a change | 10 days (contract); the previous owner may take it back meanwhile |
Proof token (sap_…) | 60 to 1800 seconds, default 1800 |
Proof (its refresh token, sapr_…) | 900 days; a User verification proof ends with its sign-in |
| Idempotency results | 24 hours; 10 minutes for responses carrying a new secret; an unfinished request holds its key for at most 120 seconds |
| Webhook deliveries | retried for 72 hours after the event (or after a replay) |
| Discovery document and JWKS | cacheable for 5 minutes |
| App credentials | verified results are cached for 60 seconds per server |
Sizes and counts
| What | Limit |
|---|---|
Handle (after c: / si:) | 3 to 30 characters of a-z 0-9 - _, case-insensitive (contract); reserved words: admin, administrator, root, system, support, help, security, silicon-accounts, account, silicon, silicons, carbon, carbons, api, www, mail, null, undefined, me, owner, staff |
| uuid | a-z A-Z 0-9, case-sensitive; 3 characters, then 4 once every 3-character uuid is used (contract); never reused |
| App id | 3 to 30 characters of a-z 0-9 - _, as Silicon Apps creates them (my_app, 2fa-tool); older ids of 2 to 40 characters of a-z 0-9 - starting with a letter (dm) keep working |
| Emails per Carbon / phones per Carbon | 10 / 10 (contract) |
| Display name | 1 to 100 characters, no control characters |
| Date of birth | in the past, not before 1900-01-01; a Silicon's is its creation date |
| STK | generated: stk- + 12 hex characters; chosen: stk- + 8 to 32 hex characters (contract) |
| URLs (photos, webhooks, …) | 2048 characters |
client_label | 100 characters (longer ones are cut) |
| Profile photo | 2 MB (2,097,152 bytes); PNG, JPEG, WebP or GIF; 8192 px a side; 50 megapixels |
| Request body | 64 KB; photos 2 MB; PATCH …/signin-config 512 KB; imports 50 MB; Silicon Apps sync 5 MB |
| Time budget per request | 30 seconds; photo uploads and sync 60 seconds; imports 5 minutes (then 503 request_timeout) |
| Page size | 1 to 200, default 50 |
Idempotency-Key | 1 to 200 visible ASCII characters |
X-Request-Id kept from the client | 1 to 128 characters of A-Z a-z 0-9 - _ . : |
| Redirect URIs / allowed origins / allowed email domains per app | 50 / 50 / 100 |
| Branding | logo_height 16 to 96 px, radius 0 to 40 px, inline logos 128 KB each, text contrast at least 4.5:1, copy.title 80 and copy.subtitle 200 characters |
| Import | 100,000 rows; 200 columns; column names 200 bytes; values 8 KB; lists 50 items; 10 emails and 10 phones per row; external_id 255 characters; display names cut at 100 characters |
| Concurrent import parses | 2 per server; a request waits up to 30 seconds for a slot, then 503 imports_busy (Retry-After: 15) |
| Webhook replay | 100 deliveries per request |
| Proof scopes | 20 per proof, each 1 to 100 characters of A-Z a-z 0-9 _ . : / - |
| App verification receiving apps | exactly 1 per proof |
| Report message | 1 to 10,000 characters; pr_url https |
| Telemetry batch | 50 events; name ^[a-z0-9_.]{1,64}$; source 64 characters; step 200 characters; data 8 KB |
| Sign-in history shown to an app per member | the last 20 |
Webhooks and messages
| What | Value |
|---|---|
| Answer time for a delivery | 10 seconds; a 2xx in time is success |
| Retry schedule | 10 s, 30 s, 1 min, 5 min, 15 min, 30 min, then hourly |
| Give up | 72 hours after the event (or after a replay): failed, replayable |
| Redirects | not followed |
| Signature timestamp tolerance (Rust client default) | 5 minutes |
| Email and SMS sending | at most 8 attempts; a code's message stops retrying once the code expired |
Silicon keys
| What | Value |
|---|---|
| Live keys per Silicon | 10 |
Assertion lifetime (exp - iat) | at most 300 seconds (30 seconds of clock skew allowed) |
Assertion jti | 1 to 200 characters, each used once |
| Key name | at most 100 characters |
Trust relationships and identity tokens
| What | Value |
|---|---|
| Live trusts per Silicon | 20 |
| Conditions per trust | 1 to 10 |
| Condition claim name / value | 1 to 100 characters of a-z A-Z 0-9 _ - . : / / 1 to 500 characters |
| Issuer / audience of a trust | 300 / 400 characters |
| Trust name | at most 100 characters |
| Outside token | 16 KB |
Clock skew on an outside token's exp, nbf, iat | 30 seconds |
| Fetching an issuer's discovery document or JWKS | https, 5 seconds to connect, 10 seconds in all, 256 KB, no redirects |
| Identity token audiences per Silicon | 0 to 20 (none until the custodian allows one), each at most 400 characters |
| Identity token signing key | RSA 2048, RS256 |
Event streams
| What | Value |
|---|---|
Open streams (GET /v1/events/stream) | 5 per app or account; 500 per server (429 too_many_streams / 503 stream_capacity_reached, with Retry-After) |
| How often a stream looks for new events | every second, at most 100 events per read |
Heartbeat (: heartbeat) | after 15 seconds without events |
Reconnect delay told to clients (retry:) | 5 seconds |
| Credentials checked again | every 30 seconds |
| Longest stream | 1 hour, then stream.closed with max_duration: reconnect with Last-Event-ID |
Event types in ?types= | at most 20 |
| Subscriptions per app | one webhook and one stream |
Retention
Every 10 minutes a sweep deletes, in batches:
- sign-in flows, 1 day after they expired;
- authorization codes, short-lived tokens and device codes, 7 days after they expired;
- verification codes, 1 day after they expired;
- expired idempotency results;
- id reservations, 1 day after they ended;
- sign-up sessions, 7 days after they expired or were used;
- used
jtis of Silicon key assertions and of outside tokens, once they expired; - rate-limit windows older than a day.
Proof tokens are deleted 1 day after they expire, and every token of a proof 30 days after the proof ended.
History is never deleted: sign-ins, id changes, custodian transfers, proofs, sign-in setup versions and the audit log stay for good.