Rate Limit
Overview
The Appmax API enforces request limits at two levels to ensure stability and availability for all integrators. Your request must pass both levels to be processed.
Control levels
Level 1 — Per-credential limit
Applied per merchant client_id. Controls request rate and total volume.
| Metric | Limit | Description |
|---|---|---|
| Burst | 50 requests | Maximum simultaneous requests (instant peak) |
| Rate | 5 requests/second | Sustained request rate |
| Monthly quota | 100,000 requests/month | Total requests per month (resets on the 1st) |
Level 2 — Per-route limit
Applied per email + source IP. Controls individual route usage.
| Route type | Limit | Window |
|---|---|---|
| Transactional routes (default) | 60 requests | 1 minute |
| Sensitive operations (login, credentials) | 5 requests | 1 minute |
TIP
In practice, you can burst up to 50 requests instantly, then maintain a sustained rate of 5 requests per second without being throttled. If the limit is exceeded, the request is rejected with 429.
Monthly quota
In addition to the per-second rate limit, there is a monthly limit of 100,000 requests per client_id:
- The counter is incremented on each request
- Automatically resets on the first day of each month
WARNING
When the monthly quota is exceeded, all requests are blocked with 429 until the next month.
INFO
These limits exist to ensure platform security and stability, but they are fully flexible. If your integration needs higher limits, don't hesitate to reach out to our team — we'll adjust them to fit your needs.
Rate limit response
When the limit is exceeded, the API returns HTTP 429 status with informational headers:
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
Retry-After: 45{
"message": "Too many requests",
"retryAfter": "45(s)"
}| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum number of requests allowed in the window |
X-RateLimit-Remaining | Requests remaining in the current window |
Retry-After | Seconds until you can retry |
Best practices
Implement retry with exponential backoff. When receiving
429, wait for the time indicated in theRetry-Afterheader. If no header is present, use exponential backoff (1s, 2s, 4s, 8s...).Use queues for batch operations. If you need to create many orders or customers, queue the requests and process them respecting the 5 req/s rate.
Cache the Bearer token. The token lasts 1 hour. Reuse it instead of generating a new one per request — authentication also consumes quota.
Monitor rate limit headers. Use
X-RateLimit-Remainingto adjust your speed before hitting the limit.Group operations when possible. Prefer creating customer + order in quick sequence rather than multiple distributed calls.
Retry with backoff example
func requestWithRetry(client *http.Client, req *http.Request) (*http.Response, error) {
maxRetries := 3
for attempt := 0; attempt <= maxRetries; attempt++ {
resp, err := client.Do(req)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusTooManyRequests {
return resp, nil
}
resp.Body.Close()
retryAfter := resp.Header.Get("Retry-After")
wait, _ := strconv.Atoi(retryAfter)
if wait == 0 {
wait = 1 << attempt // backoff: 1s, 2s, 4s
}
log.Printf("Rate limited, retrying in %ds (attempt %d/%d)", wait, attempt+1, maxRetries)
time.Sleep(time.Duration(wait) * time.Second)
}
return nil, fmt.Errorf("rate limit exceeded after %d retries", maxRetries)
}