Limits
Rate limits apply per API token, per minute, on a rolling 60-second window.
| Token type | Limit |
|---|---|
stp_test_... (sandbox) |
600 requests / minute |
stp_live_... (production) |
120 requests / minute |
Test tokens get a much more generous limit so development and CI don't feel throttled. Production traffic patterns for STP lodgement don't come close to 120/min for normal customers — if you need more, email support@beeswaxapp.com and we'll discuss a custom arrangement.
Why per-minute, not per-second?
STP lodgement is bursty by nature. You typically send a batch of pay events once per fortnight and nothing in between. A per-second limit would make that burst feel hostile. A per-minute limit lets you push through your batch quickly without needing sophisticated client-side throttling.
Response headers
Every API response includes these headers:
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 97
X-RateLimit-Limit— your current limit. For most customers this is fixed; if we raise it for you via custom agreement it will be reflected here.X-RateLimit-Remaining— how many more requests you can make before hitting the limit. Drops by 1 per request. Resets when the minute rolls over.
When you hit the limit, we respond with 429 Too Many Requests:
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0
Retry-After: 60
Content-Type: application/json
{
"error": "Too Many Requests",
"message": "You've exceeded the rate limit of 120 requests per minute.",
"code": "rate_limit_exceeded"
}
The Retry-After header tells you how many seconds to wait. It's always ≤60 for per-minute limits.
Backoff strategy
When you get a 429:
- Read
Retry-Afterand sleep at least that long before retrying. - Use jitter — add a random 0–1s to the wait so multiple clients don't all retry at the same instant. This matters if you're running parallel workers.
- Exponential backoff for repeated 429s — if you hit another 429 right after the wait, double the wait and try again. Cap at 5 minutes.
- Give up eventually. If you're still being rate limited after 10+ retries, something is wrong with your traffic pattern. Check your code for runaway loops before retrying indefinitely.
Example pseudo-code:
def api_request_with_backoff(req, max_attempts: 10)
attempt = 0
wait = 0
loop do
sleep(wait) if wait > 0
response = send(req)
return response unless response.status == 429
attempt += 1
raise "Rate limit exhausted" if attempt >= max_attempts
retry_after = response.headers["Retry-After"].to_i
jitter = rand(1.0)
wait = [retry_after, wait * 2].max + jitter
wait = [wait, 300].min # cap at 5 minutes
end
end
Proactive throttling
You don't need to wait for a 429 to back off. Watch the X-RateLimit-Remaining header and slow down when it drops below a threshold:
remaining = response.headers["X-RateLimit-Remaining"].to_i
if remaining < 10
sleep(1) # approaching the limit, breathe a little
end
This is strictly optional — our enforcement is server-side and safe to ignore. But it produces cleaner logs and friendlier behaviour.
What counts against the limit?
Every request that reaches the API base controller counts, including:
- Successful requests (2xx)
- Validation failures (422)
- Forbidden (403)
- Not found (404)
Requests that don't count:
- Auth failures before the token is recognised (401) — counted separately at the IP level
- 429 responses themselves (we don't double-charge you)
- Internal redirects or Rails proxy noise
Multiple tokens
If you have multiple tokens for the same account — say, one for your production server and another for a CI pipeline — they have independent rate limits. One doesn't consume the other's quota.
Creating more tokens is not a workaround for rate limits. Our terms of service require one token per logical integration, not per request. If you need more throughput, email us.
Bulk operations
If you're lodging pay events for hundreds of employers at once (e.g. an accounting practice at EOFY), batch the work:
- Collect all your pay events in memory first
- Spread them across the minute rather than all at once
- Use webhooks instead of polling for submission status — that saves ~1 request per submission per poll
A Practice-plan bookkeeper with 50 clients lodging weekly would send roughly 50 pay event creates + 500 item adds + 50 mark-reads + 50 submits = ~650 requests, comfortably fitting in 10 minutes of steady 120/min throughput.
Enterprise / high-volume needs
If your realistic production volume is genuinely above 120 req/min sustained, we can work out a custom arrangement. Email support@beeswaxapp.com with:
- Expected peak rate (requests/minute)
- Typical daily volume
- Whether the traffic is constant or bursty
- Your use case (so we know what we're enabling)
Answer: most customers who think they need more don't. Normal STP volume is low. The 120/min limit is to catch runaway loops, not to upsell.