Rate Limits
Per-merchant fixed-window rate limits, response headers, and how to handle 429 responses.
halfin enforces per-merchant fixed-window rate limits. Limits are keyed by merchant account (API key environment), not by IP address.
Limits
| Operation | Limit | Window |
|---|---|---|
| Create Invoice | 60 requests | per minute |
| Create Payout | 20 requests | per minute |
| Read endpoints (GET list/get) | 300 requests | per minute |
| Global per-IP backstop | 1000 requests | per minute |
The global per-IP backstop applies as a secondary safeguard across all endpoints.
Rate limit headers
Every response includes the current counter state:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 54
X-RateLimit-Reset: 1751234567| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed in the window |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix timestamp (seconds) when the window resets |
429 response
When the limit is exceeded, the API returns 429 Too Many Requests with error code rate_limit_exceeded:
{
"error": {
"code": "rate_limit_exceeded",
"message": "rate limit exceeded, try again later"
},
"meta": { "request_id": "req_0000000000000001" }
}There is no Retry-After header. Use X-RateLimit-Reset to determine when the window resets.
Best practices
- Use webhooks rather than polling to receive payment status updates.
- Cache
/v1/ratesand/v1/currenciesresponses — they change infrequently. - Back off on 429 using
X-RateLimit-Resetto calculate wait time. - Batch operations server-side rather than making one call per user action.