Rate Limiting
API rate limits, identities, and backoff behavior.
Rate Limiting
VanityPass applies application-layer rate limits to every /v1 request. The global limit uses the first verified identity available: JWT user, tenant app/API key, then client IP. Invalid credentials do not create a new bucket; those requests fall back to the trusted client IP.
Tenant-configured quotas may apply independently. When more than one policy applies, a request must pass every policy.
Default security limits
| Surface | Identity | Default |
|---|---|---|
All /v1 endpoints | Verified user, then verified app, then client IP | 100 requests / 10 seconds |
| Authentication endpoints | Client IP | 30 requests / minute |
| Authentication target | HMAC-protected email/account plus app | 5 requests / 5 minutes; repeated lockout: 10 minutes |
| User search | Client IP plus verified user/app | 60 requests / minute per IP; 30 requests / minute per user |
| Experiences catalog | Client IP | 20 requests / 10 seconds |
| Webhooks | Client IP | 10 requests / second and 120 requests / minute |
Client IP limits apply regardless of authentication. This prevents account, token, app-header, or email rotation from bypassing the protection.
When a limit is exceeded
A rejected request returns 429 Too Many Requests and these headers:
Retry-After: positive number of seconds before retrying.X-RateLimit-Limit: maximum requests in the window that was exceeded.X-RateLimit-Remaining:0.X-RateLimit-Reset: Unix epoch second when that window resets.
HTTP/1.1 429 Too Many Requests
Retry-After: 7
X-RateLimit-Limit: 20
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1785678901
{
"status": "fail",
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Retry after the indicated delay."
}
}
Backoff strategy
Honor Retry-After as the minimum delay. Add a small random jitter before retrying so concurrent clients do not resume at the same instant. If Retry-After is unavailable, use capped exponential backoff. Stop retrying after a bounded number of attempts and surface the failure to the caller.
Do not change credentials or spoof forwarding headers to obtain another bucket. Forwarded client addresses are accepted only from the configured trusted ingress chain.