Rate limits
Every endpoint is rate limited per source IP via a sliding 60-second window in Cloudflare KV. The limits are applied by route group (not per route) so a POST /api/public/:slug/bookings and a GET /api/public/:slug/services share the same bucket.
Limits by route group
Defined in apps/api/src/index.ts. Every limit is per source IP, sliding 60-second window in Cloudflare KV.
| Route group | Limit | Window | Notes |
|---|---|---|---|
| POST /api/auth/login | 10 | 60s | Per IP |
| POST /api/auth/register | 5 | 60s | Per IP |
| POST /api/customer-auth/login | 10 | 60s | Per IP |
| POST /api/customer-auth/register | 5 | 60s | Per IP |
| POST /api/customer-auth/forgot-password | 5 | 60s | Per IP |
| /api/public/* | 30 | 60s | Public booking flow |
| /api/me/* | 60 | 60s | Customer self-service |
| /api/webhooks/* | 60 | 60s | Stripe inbound |
| /api/ai/* | 30 | 60s | Owner AI chat / log / insights / smart-reply |
| /api/ai-public/* | 30 | 60s | Public booking assistant chat |
| /api/businesses, /api/services, /api/staff, /api/bookings, /api/customers, /api/payments, /api/admin | none at the route group | — | Inherits only the global Hono logger. No per-IP KV counter is configured in apps/api/src/index.ts. |
How the limiter works
The rateLimit middleware reads cf-connecting-ip and increments a counter in KV under the key {prefix}:{ip}. The counter expires with the window. When the counter would exceed the limit, the request is rejected with HTTP 429 before the handler runs.
429 response
The 429 response is a bare object with the error code as a string:
{
"error": "rate_limited"
}Retry-After header (in seconds, computed from KV's window-reset timestamp). The X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers are NOT set today.Backoff strategy
- On 429, wait until
Retry-Afterseconds before retrying. - If no
Retry-After, wait 60 seconds (default window). - Exponential backoff: multiply wait by 2 on each consecutive 429.
- Cap at 5 minutes between retries.
- After 5 consecutive 429s, give up and contact support.
How to request a rate limit increase
The route-group limits in the table above are the only limits in the API today — there is no separate per-tier tier multiplier (free / pro / enterprise) wired into the rate limiter. Custom limits per route are not currently exposed. To request a change, contact hello@netwit.ca.
Email hello@netwit.ca or call +1-604-206-8169. NetWit responds in 1 business day.