Respect the rate limits
Every operation — single calls, batched calls, and reads — draws from one per-server budget:
When you exceed the budget, calls start returning
nil/false (HTTP 429).
Some expensive methods also carry their own, tighter limit — for example
getLeaderboard allows one call every 30
seconds per server. These are noted on the relevant method.
Don’t call the same endpoint repeatedly
The single biggest cause of throttling is re-fetching data that hasn’t changed. Fetch it once, keep the result, and reuse it. Fetch on the event that actually changes the data instead:Cache reads in your own code
For data you read often, keep a small in-memory cache keyed by user id and refresh it only when it matters (on a timer, or after you change the underlying data).A few methods are already cached for you per player for the length of their
session —
getUserPermissions
and getUserRoles. You still
shouldn’t call them in a loop, but you don’t need to build your own cache for
them.Batch related operations
If you need to perform several operations at once, send them together withapiBatch instead of firing many separate calls.
One batch of 20 counts the same against the budget as 20 singles, but it’s a single
round-trip — faster, and far less likely to interleave with other work.
Debounce player-triggered actions
Any call a player can trigger (a button, a command, a chat trigger) needs a guard, or a single player can spam your budget. Track a per-player timestamp and reject calls that come too fast.Handle failures without hammering
Anil or false return can mean a rejection or a transient network issue.
Always check the result before using it, and if you retry, back off — never
retry in a tight loop.
Run independent calls concurrently — within reason
Because each call yields, running several independent calls sequentially adds up their wait times. Usetask.spawn to overlap them — but don’t fan out hundreds
at once, or you’ll hit the budget instantly.
Keep payloads small and reuse identifiers
- Each operation’s
argspayload is capped at 24 KB. Send only what the method needs — don’t forward large tables or entire data models. - When you start a session, keep the returned
sidand pass it to every follow-up call rather than fetching the session again to find it. - Remember timestamps are Unix epoch milliseconds (see
Core Concepts → Timestamps);
os.time()returns seconds, so multiply by1000.
Quick checklist
No API calls inside per-frame or
while true loops.Reads that don’t change are cached (or fetched once on join).
Multiple operations are grouped into a single
apiBatch.Player-triggered actions are debounced.
Every result is checked for
nil/false before use.Retries use backoff, never a tight loop.
Next steps
Core Concepts
Actor object, return conventions, yielding, and the full rate-limit rules.
apiBatch
Run several operations in a single request.

