Rate Limits & Security
Rate limits
Every route is throttled per minute, keyed per credential/caller. Design your integration to back off and retry rather than hammer a limited route — these are current defaults and may be tuned over time.
| Route | Default limit |
|---|---|
| Token exchange (either credential kind — shared budget) | 10/min |
/identity/link | 10/min |
/duty | 60/min |
/lookup/*, /warrant-check, /bolo-check, /civilian, /vehicle | 60/min |
/bolo | 20/min |
/bolo/:boloId/resolve | 20/min |
/citation, /arrest, /civilian/claim | 10/min |
/panic | 6/min |
/911 | 20/min |
/911/self-assign | 20/min |
/location | 600/min |
/waypoint | 300/min |
/mdt-handoff | 10/min |
/presence | 10/min |
The token exchange endpoint has one combined budget per caller regardless of which credential kind you're using — they're two paths to the same underlying exchange, not two independent allowances.
/duty has a second, separate limit on top of its 60/min above: new
Kestrel accounts created via its auto-provision path are capped at 20/hour
per credential (FIVEM_AUTO_PROVISION_RATE_LIMIT_PER_HOUR) — spam
protection against a flood of brand-new accounts, not a general request
budget. An already-provisioned player calling /duty repeatedly never
touches this cap; it only counts genuinely new account creation.
Security notes worth knowing before you build against this
- Revocation is passive. A revoked credential's already-issued token keeps working until it naturally expires (bounded by the 12-minute TTL) — there's no instant kill switch on an in-flight token. Rotate promptly if you suspect a leak.
- Every integration-authenticated write is audit-logged against the credential's own identity — never anonymized.
- An integration credential is scoped to your organisation only. There's no cross-tenant path even if a token leaked.
- Treat credentials like a password. Kestrel's own design assumes a
credential will eventually leak, and limits blast radius accordingly
(short-lived tokens, independent per-credential revocation, audit
trails) rather than assuming it can't happen. Never commit a
clientId/clientSecretto source control. scopesis only partially enforced on the FiveM Bridge. Three routes actually check it:POST /citation(needsfivem.citation.issue),POST /arrest(needsfivem.arrest.log), andPOST /bolo(needsfivem.bolo.trigger) — afivem-kind credential missing the matching scope gets a clean403from these three. Every other FiveM Bridge endpoint (duty, lookups, warrant-check, bolo-check, identity-link, mdt-handoff, location, waypoint, presence, 911) ignores thescopesclaim entirely and is reachable by any validfivem-kind credential regardless of what's configured on it. Don't rely on FiveM Bridge scopes as a permission boundary outside those three routes. This is different for the API credential — there, scopes are real, validated at creation, and enforced on every request.