Rate limits
MidasPay protects the platform and downstream acquirers against overload. Concrete per-merchant quotas (requests per second, burst allowances) are set contractually and administered in the Merchant Portal — they are not published here because they vary by merchant tier, channel and region.
If you need to run a flash sale, back-fill a month of transactions, or otherwise expect sustained high throughput, talk to your MidasPay account manager ahead of time to raise your quota. Hitting a limit at runtime cannot be resolved quickly.
When you've been throttled
A throttled request is rejected with HTTP 429 ResourceExhausted and a
MidasPay error code in the response body. The specific code depends on
what was throttled:
| Code | Meaning |
|---|---|
CHANNEL_MARKETING_BUDGET_LIMITED | The channel's marketing / promotional budget is exhausted. Retry later or disable the promotion. |
CHANNEL_MARKETING_TRANSACTIONS_LIMITED | The channel has hit its transaction-count cap for this merchant or campaign. Retry later. |
Additional 429 conditions may be returned when a global platform limit is hit. In all cases, treat 429 as a retryable failure — pause and try again later rather than giving up.
See Error codes for the full catalogue.
Recommended client back-off
Use exponential back-off with full jitter on 429 and on network
errors. Cap the retry budget so runaway loops can't pile up:
func call(ctx context.Context, req Request) (*Response, error) {
const (
base = 200 * time.Millisecond
maxSleep = 30 * time.Second
maxAttempts = 6
)
for n := 0; n < maxAttempts; n++ {
resp, err := do(ctx, req)
// 2xx / non-retryable 4xx — stop
if err == nil && resp.StatusCode != 429 && resp.StatusCode < 500 {
return resp, nil
}
// Exponential with full jitter
delay := time.Duration(rand.Int63n(
int64(min(maxSleep, base*(1<<n)))))
select {
case <-time.After(delay):
case <-ctx.Done(): return nil, ctx.Err()
}
}
return nil, ErrTooManyRetries
}
Retrying a 429 with no delay just slams the same bucket — leading to cascading failures. Always apply at least a few hundred milliseconds of jittered delay before retrying.
Designing to stay within limits
- Batch where possible. List endpoints return up to 100 — or 5000 for merchant quotes — records per call. Prefer a small number of large pages over many small ones. See Pagination.
- Spread bulk jobs over time. Reconciliation that pulls a month of data should scatter calls across many minutes, not tight loops.
- Cache quotations.
MerchantQuote.GetQuotationInfochanges only on contract renegotiation — cache for at least 15 minutes. - Idempotency is your friend. A retry-safe client can pause for seconds without losing semantics; see Idempotency.
- Use webhooks for state. Don't poll order-query in a tight loop — subscribe to the payment-paid event instead. See Webhooks.
FAQ
Where do I see my current quota? In the Merchant Portal → Developer → API quotas. If you can't find it, contact your MidasPay account manager.
Are sandbox and production quotas the same? Sandbox quotas are generally lower to prevent noisy-neighbour testing from affecting the shared environment. Plan production load tests separately with your account manager.
Are webhook deliveries throttled? Inbound webhook delivery (MidasPay → you) is rate-managed separately, and the retry policy is documented in Webhook retry policy.
See also
- Error codes — full catalogue including 429 responses.
- Idempotency — so retries are always safe.
- Pagination — to shape big reconciliation jobs.
- Webhooks — the preferred alternative to polling.