On this page0
Unfamiliar word? See Glossary: words used in these docs. Looking for the tasks in order? Begin at Start Here.
Reference
Not a developer? The step-by-step guides begin at Start Here, and a problem on your screen is in When something goes wrong.
Rate, Size & Time Limits
What It Does
A rate limit is a cap on how many times something may be tried in a short time. Zonitix uses them to slow down password and code guessing. An administrator has nothing to switch on: the limits are built in and cannot be changed from the app. You meet them in two ways. A person who mistypes their password or code many times is told to wait and try again later. A script that calls the API too quickly is refused until it slows down. Separately from these limits, 5 wrong passwords in a row lock that one account for 15 minutes.
The plain explanation is above. This part is for IT and developers: the exact settings, permission names, API addresses and data fields behind it.
Your gateway rate-limits the sensitive routes. Limits are backed by Redis, so they hold across restarts and replicas. This page also lists the fixed request-size limits and the fixed lifetimes of links, keys and lockouts.
Configured Limiters
These are the limiters configured on the gateway. Paths are shown without the /api/v1 prefix; both forms share one budget. Ordinary authenticated read/write traffic is not globally throttled — because your instance serves only your company, the limiters exist to blunt credential guessing and abuse of high-impact routes, not to ration capacity between tenants.
| Routes | Limit | Why |
|---|---|---|
| /auth/login, /auth/password/change, /auth/magic-link/verify, /auth/accept-terms, /auth/invite/inspect, /auth/invite/accept, /auth/sso/login, /auth/sso/saml/login, /auth/sso/saml/acs, /auth/sso/saml/metadata, /auth/sso/callback | 20 failed / 15 min | Brute-force protection, per client IP. Only failed requests count; a successful one does not use the budget. |
| /auth/magic-link/request | 30 / 15 min | Asking for an emailed sign-in link. Per client IP, and every request counts, successful or not. |
| /auth/mfa/setup/init, /auth/mfa/setup/confirm, /auth/mfa/verify, /auth/mfa/verify-recovery, /auth/webauthn/register/*, /auth/webauthn/authenticate/*, /auth/webauthn/login/*, DELETE /auth/webauthn/credentials/:id | 20 failed / 5 min | Second-factor routes, per client IP, failed requests only. The per-account limits on the MFA Enforcement page (5 wrong codes per challenge) apply on top. |
| POST /auth/sudo, POST /auth/webauthn/sudo/verify | 5 failed / 15 min | Step-up re-authentication guards the most damaging actions. Counted per client IP and signed-in user; a successful step-up does not use the budget. |
| GET /auth/webauthn/sudo/options | 30 / 15 min | Fetching a passkey step-up challenge. Same IP-and-user key as the row above, counted separately. |
| GET /auth/setup/status | 3,000 / 15 min | Per client IP. A read-only status check that the app polls, so it has a wide budget. |
| Every other /auth/setup/* route | 30 / 15 min | Blocks guessing of the one-time setup key during first-run setup. |
| Personal API tokens (any route) | 300 / min | Counted per token, not per IP. |
| /scim/v2/* | 600 / min | Per client IP. Sized for an identity provider pushing a large directory. A refusal uses the SCIM error format. |
| /agent/* | 300 / min | Per client IP, for device agents checking in. Redeeming an enrolment code (POST /agent/mdm-enroll-redeem) has its own budget of 30 / 15 min. |
| /ai/* | 30 / min | Per signed-in user. The assistant runs on your own server and is CPU-bound. |
| /security-lab/* (writes) | 20 / min | Per signed-in user. GET requests are not counted; scans and probes are heavy. |
| /signature/sign/* | 80 / 15 min | Per client IP, for the public document-signing pages. |
| /recruitment/public/*, /recruitment/webhooks/*, /shared/*, /public/phishing/*, GET /auth/sso/pending | 240 / min | Per client IP, for pages that need no sign-in. Blunts link guessing and webhook spam. Like every limit in this table, it is applied by the gateway. |
| GET /public/phishing/l/:token | 120 / min | Per client IP, on top of the 240 / min public limit above. |
| /training-content/* | 6,000 / min | Per client IP. Only GET and HEAD requests are accepted on this path. |
| /recruitment/public/*, /shared/* (non-GET) | 30 / 15 min | Per client IP. A tighter budget for public form submissions such as a job application. |
| GET /shared/verify/:runId | 20 / 10 min | Per client IP, for the public report-verification page. |
A refused request gets 429 with a JSON error message. If the gateway cannot reach Redis, most limiters fail closed: the request is refused with 503 and Retry-After: 5 instead of being let through uncounted. The exceptions let requests through while Redis is down: the 240-per-minute public-page limiter, the phishing landing-page limiter, the training-content limiter, the SCIM limiter, the personal API token limiter and the report-verification limiter.
How The Client Address Is Determined
In plain words: the “client IP” is the public address the request came from, as reported by the network edge in front of your server. Everyone in one office usually shares one such address, so they share one allowance and one rule.
Wherever these docs say client IP or address for a rate limit, a country or IP rule, or an audit entry, this is the value the gateway uses, in this order.
| Used for | Value, in order | Notes |
|---|---|---|
| Country and IP rules, and the auto-block detectors | The CF-Connecting-IP request header. If it is absent, the address of the peer on the connection itself. | X-Forwarded-For and X-Real-IP are not read for these rules. |
| Rate limits described as "per client IP" | The CF-Connecting-IP request header. If it is absent, the gateway’s own request address, worked out with one proxy hop trusted. | Three limiters read only the gateway’s own request address and not the header: device agent check-ins, the public document-signing pages, and the 30-per-15-minutes limit on first-run setup. |
| The address written on an audit entry | The CF-Connecting-IP header, then the first address in X-Forwarded-For, then X-Real-IP, then the peer on the connection. | The gateway passes these headers on to the service that writes the entry. The later choices apply only when the first header is absent. |
- What is trusted. The gateway expects the network edge to set
CF-Connecting-IPon every request it passes into the tunnel. The gateway publishes no port on the server, so a request from outside reaches it only through that tunnel; the path is drawn under Request Path And TLS. - One form of the address. For the country and IP rules, the auto-block detectors, the rate limits that read the header, and the audit entry, the prefix
::ffff:on an IPv4 address written in IPv6 form is removed, so the same client is the same key either way. The three limiters that read only the gateway’s own request address are not part of that statement. A rate-limit key passes through the limiter library’s address function, which counts an IPv6 network as one client, not each address in it. - Private addresses. An address in a private or loopback range is never subject to a country or IP rule, as listed under Evaluation Order & Safety.
- What follows for you. People behind one office or VPN address count as one client for a per-IP limit and match one IP rule. A limit counted per signed-in user or per token is not affected by the address at all.
Request Size Limits
Every limit below is fixed in the product. A JSON body over its limit is refused with 413; the rows say where an upload answers differently. Paths are shown without the /api/v1 prefix. Separately from size, the gateway allows 5 minutes for a whole request.
| Request | Limit | Notes |
|---|---|---|
| Any /auth/* JSON body | 100 KB | Gateway, before authentication. 413. |
| POST /auth/settings/branding, /auth/settings/security/access-control | 10 MB at the gateway, then 1 MB | The gateway accepts up to 10 MB once the caller is authenticated; the identity service behind it accepts 1 MB. 413. |
| POST /auth/audits/active, /auth/audits/history, /auth/security-lab/sbom-scan, /auth/security-lab/intel-import | 10 MB | Gateway, after authentication; the service behind accepts the same. 413. |
| POST /auth/sso/saml/acs | 100 KB form, at most 5 fields | Gateway. The limit is on the URL-encoded form, so the usable SAMLResponse is somewhat smaller. |
| /scim/v2/* | 1 MB | JSON or SCIM JSON. 413. |
| Résumé upload by a signed-in user (parse, screen, referral) | 5 MB, one file | 413. |
| Public job application (POST /recruitment/public/apply/:jobId, /recruitment/public/apply-general) | 5 MB, one file | 400 with "The résumé must be a single file under 5 MB." |
| Offer supporting document (POST /recruitment/offer-documents) | 10 MB, one file | 400 with "File is too large (max 10 MB)." |
| Compliance evidence upload | 25 MB, one file | Up to 20 other form fields of 64 KB each. 413. |
| User import (preview and commit), training-completions import | 2 MB | JSON. 413. |
| Employee document content | 10 MB | Sent as the raw request body. 413 with "The file is larger than 10 MB." |
| Training SCORM package | 50 MB zipped | At most 150 MB and 2,000 files once unpacked. |
| Training video | 95 MB | Read as it arrives and stored in sealed 1 MB chunks. |
| Device agent installer upload | 150 MB | Sent as application/octet-stream. |
| POST /agent/mdm-enroll-redeem | 4 KB | JSON. |
| Any other JSON body | 100 KB, 2 MB, 10 MB or 25 MB | Outside /auth the gateway streams the body through and the service that receives it applies its own limit: 100 KB for identity, user management, workflows, recruitment and the assistant; 2 MB for devices; 10 MB for compliance, integrations, Security Lab and logging; 25 MB for e-signature. |
Caps On What Comes Out
| Output | Cap |
|---|---|
| Audit log export | 50,000 rows per export |
| Log forwarding, one event | 64 KB. A larger event is sent with its payload replaced by a marker, never cut off part-way. |
| Log forwarding, one batch | 200 events or 1 MB |
Uploaded Files: What Is Checked
Besides its size, an uploaded file is checked for its type, and in some routes for its name and its content. Which check runs depends on the route. Where a row says first bytes, the product compares the start of the file with the signature of the format it claims to be. For PDF, PNG and JPEG that means a file renamed to one of those endings is refused. A Word or Excel file is checked for the zip container signature the two formats share.
| Upload | What is checked | When it fails, or what is recorded |
|---|---|---|
| Résumé read by the product (parse, AI screen, referral, public application) | The document parser reads it. The file name must end in pdf, png, jpg, jpeg, docx, xlsx, txt or csv. For pdf, png and jpg the file’s first bytes must be that format’s signature; a docx or xlsx must start with the zip container signature; a txt or csv must decode as UTF-8 text. | Reading a résumé to pre-fill the candidate form: 200 with empty fields and a warning to enter the details by hand. A résumé screened after it was submitted: the check runs in a background job after the request has been answered, so the file is refused there and no error status is returned to the person who sent it. |
| Public job application | Before anything else, the file name must end in .pdf, .docx or .txt. The stored copy and the screening then pass the résumé checks in the rows above and below. | 400 with "The résumé must be a PDF, Word (.docx), or plain text file…". |
| Any file kept by the shared file store: résumés, offer supporting documents, compliance evidence | The file name must end in .pdf, .png, .jpg, .jpeg, .docx, .txt, .xlsx or .csv. The name the uploader gave is not used on disk: the file is stored under a random identifier with that ending, and it is encrypted before it is written. | Offer documents: 400 with "Unsupported file type…". |
| Offer supporting document | As the row above. The label and the original file name kept for display have angle brackets removed and are cut to 120 and 200 characters. | Written to the audit log as OFFER_DOCUMENT_UPLOADED. |
| Compliance evidence | As the shared file store. The server computes the SHA-256 of the bytes it received and returns it with the stored file’s address. A download request whose file name contains "..", "/" or "\" is refused. | The hash, size and control are written to the audit log as COMPLIANCE_EVIDENCE_UPLOADED. |
| Finance document and invoice import | The document parser’s check on the file name and the start of the file, as in the first row, with its own 10 MB ceiling on the content. | 400 naming the mismatch or the size. |
| Employee document | PDF, PNG and JPEG are recognised by their first bytes. A Word or Excel file must start with the zip container signature and is told apart by the parts listed inside the container; when that list does not settle it, the ending of the document’s name (.docx or .xlsx) is used. The document’s title has path and quote characters and line breaks replaced with spaces and is cut to 180 characters. | 415 when none of those matches; 400 for an empty file. |
| Training SCORM package | The zip’s file list is read before anything is unpacked. Refused: a zip64 or multi-part archive, more than 2,000 entries, more than 150 MB unpacked, and any entry whose name is empty, longer than 400 characters, holds control characters or a backslash, is an absolute path, or has a "." or ".." segment. imsmanifest.xml must be at the top level and the start file it names must be in the package. | 400 with the reason in plain words. |
| Training video | The first 12 bytes must be an MP4 or a WebM file. The file name and the type the browser declares are not used. | 415 for anything else; 400 for an empty file. |
Lifetimes And Lockouts
These windows are fixed in the product and are not rate limits: each one belongs to a single link, key, account or grant. The session lifetime is the one an administrator can change; it is on API Authentication.
| What | Limit | What happens |
|---|---|---|
| Invitation link | 72 hours, single use | Sending a new invitation replaces the old link. A used, replaced or expired link answers 410. |
| First-run setup key | 72 hours from when the server is built | After that the key answers 410 with "This setup key has expired. Contact your provider for a new one." |
| Wrong setup keys | 10 from one address in 15 minutes | Setup then pauses for that address for 15 minutes and answers 429 with "Too many attempts. Please wait, then try again." 200 wrong keys from all addresses together pause setup for everyone for 15 minutes. The counters are held in memory and start again when the identity service restarts. |
| Wrong passwords | 5 in a row | That account is locked for 15 minutes. |
| Step-up (confirming a sensitive action) | 15 minutes | A step-up counts for 15 minutes. The server reads the window from a stored setting, sudoTimeoutMinutes, and holds any value between 1 and 60 minutes, but no screen and no API route writes that setting, so every instance uses 15 minutes. A missing or expired step-up is refused with "error": "SUDO_REQUIRED" in the response body. The status beside it is 400 on most routes, because the gateway turns a 401 from a service behind it into 400. It stays 401 on the routes the gateway passes through unchanged: removing a passkey, the diagnostics bundle, and in Security Lab starting an aggressive scan, changing a scan scope and archiving findings. Key on the error string, not the status. |
| Interim sign-in token | 5 minutes | Issued while a second factor or a forced password change is still owed. |
| Emailed sign-in link | 15 minutes | |
| SAML sign-in request | 10 minutes | The response must arrive within that time, in the same browser. |
| Support access window | 1 to 72 whole hours | Chosen by the administrator who grants it. See below. |
| Internal service token | 60 seconds | Between the gateway and the services behind it; a new one is made per request. |
Database Limits
Two limits sit between a service and the database, and a very large list or report is what reaches them. A single SQL statement may run for 60 seconds; after that the database cancels it and the request fails. A service holds at most 5 database connections at once (12 for the identity service, 10 for user management), and a request that finds them all busy waits up to 30 seconds for one. Narrow the request with a filter or a smaller page and send it again. The connection settings are on Transport & Service Trust.
Support Access
Zonitix support has no sign-in to your instance until an administrator grants one. The steps are in Give Zonitix support temporary access. A grant lasts a whole number of hours from 1 to 72 and cannot be extended: a second grant while one is live answers 409, so revoke first. Every rule the server enforces, the endpoints and what is audited are in Support Access Reference.
On Key Rotation
Session tokens are signed with HMAC-SHA-256 (HS256) using one symmetric secret held on your instance; it reaches each service as a file-based secret. Replacing that secret is a change on the server, and every token issued before the change stops verifying. Which keys exist, which can be replaced and what replacing one does is on Data Isolation, under Keys and rotation.
Standard Headers
RateLimit-* headers, so a client can back off before it is refused, and not the legacy X-RateLimit-* set. The second-factor limiter (/auth/mfa/* and the /auth/webauthn/* sign-in and enrolment routes) is the exception: it does not set either option, so do not rely on RateLimit-* headers on those routes.