Core Concepts

Rate Limits

Fixed-window limits, enforced at the edge before any Firestore read happens.

ScopeLimitWindowKeyed by
All requests (backstop)12060 secondsCaller IP
POST /v1/otp/send560 secondsApplication Client ID
POST /v1/otp/verify1060 secondsApplication Client ID
Sandbox: create echo bin201 hourCaller IP
Sandbox: deliver to echo bin3060 secondsCaller IP

What happens when you're limited

A rate-limited request returns 429 with:

{
  "error": {
    "message": "Too many OTP requests — retry in 42s",
    "code": "RATE_LIMITED"
  }
}

Design notes

Limits use fixed windows rather than a sliding/token-bucket algorithm — simpler to reason about, at the cost of allowing a short burst right at a window boundary. In practice this trades a small amount of burst tolerance for an implementation with no cross-request coordination beyond a single KV read and write per call.

The per-application OTP limits are intentionally tighter than the global backstop — they exist specifically to blunt automated OTP-spam against a single application, independent of how many different IPs the traffic comes from.

Verification attempts

Separate from rate limiting: each individual OTP request allows a maximum of 5 verification attempts before it's marked failed, regardless of how much of the per-minute verify limit remains.