Rate limits

Plugipay applies per-workspace rate limits to keep the API responsive for everyone. This page covers the limits, the headers we send, and how to handle them in your code.

Default limits

Per-workspace:

Endpoint class Limit
Read (GET) 100 requests/second
Write (POST/PUT/PATCH/DELETE) 20 requests/second
Heavy operations (export, batch endpoints) 5 requests/minute
Webhook delivery (Plugipay → you) No limit on our side, backoff on failure

These are per-workspace, not per-key. All keys on a workspace share the same buckets.

Test and live keys have separate buckets — hammering test mode doesn't affect your live capacity.

Response headers

Every API response includes:

Header Notes
X-RateLimit-Limit Bucket size (e.g., 100)
X-RateLimit-Remaining Requests left in the current window
X-RateLimit-Reset Epoch seconds when the bucket fully refills

When you exceed the limit, you get 429 Too Many Requests plus:

Retry-After: 12

That's seconds to wait before retrying. The number is conservative — you can sometimes retry sooner, but Retry-After is the contractual guarantee.

When you'd hit a limit

Most workspaces never hit limits. The defaults handle moderate-volume merchants comfortably. You'd hit them if:

  • Migration scripts. Bulk-importing 100K customers from another provider in a tight loop will saturate writes. Cap parallelism at 4-8.
  • Reporting jobs. Pulling a year of payments page-by-page can saturate reads. Use /export instead.
  • Webhook backfill. If you're re-fetching all events to rebuild local state, throttle to under 100/sec.

How to handle 429

With an SDK

All our SDKs auto-retry on 429 with exponential backoff. You don't need to do anything. If the retry budget is exhausted, the error surfaces normally.

You can tune the retry behavior:

Node:

const plugipay = new PlugipayClient({
  keyId, keySecret,
  retry: {
    maxAttempts: 5,
    initialDelayMs: 200,
    maxDelayMs: 30_000,
  },
});

Python:

plugipay = PlugipayClient(
    key_id=..., key_secret=...,
    max_retries=5,
)

With raw HTTP

Look for 429, read Retry-After, sleep, retry:

while true; do
  resp=$(curl -sS -i ... /v1/customers/cus_xxx)
  status=$(echo "$resp" | head -1 | awk '{print $2}')
  if [ "$status" != "429" ]; then break; fi
  sleep_s=$(echo "$resp" | grep -i '^Retry-After:' | awk '{print $2}' | tr -d '\r')
  sleep "${sleep_s:-5}"
done

Exponential backoff (generic)

If Retry-After isn't provided (shouldn't happen, but just in case):

attempt 1: wait 200ms
attempt 2: wait 400ms
attempt 3: wait 800ms
...
attempt N: min(2^N * 200ms, 30s)

Cap the wait at 30 seconds. Add jitter to avoid thundering herd.

Bulk operations — staying under the limit

For batch operations:

# Cap parallelism with xargs -P
plugipay payments list --since 1d --output ids | \
  xargs -n1 -P4 -I{} plugipay refunds create --payment-id {} --reason fraudulent

-P4 means 4 parallel refunds. With a 20-write/sec limit, 4 parallel × the latency per refund (a few hundred ms) usually keeps you comfortably under.

If you have a script that needs to do thousands of operations:

  1. Use idempotency keys so partial-failure retries don't double-process.
  2. Cap parallelism at 4-8 for writes, 16-32 for reads.
  3. Watch X-RateLimit-Remaining — if it drops below 10% of the limit, slow down.
  4. Use /export endpoints for read-heavy reporting instead of paginating.

Per-endpoint limits

Some endpoints have stricter or looser limits than the class default:

Endpoint Limit Reason
/v1/uploads 10/minute File uploads are heavy
/v1/payments/export 1/minute Streaming export
/v1/reports/* 30/minute Aggregation is expensive
/v1/payments (read) 200/sec Common high-volume endpoint

If an endpoint deviates from the class default, the per-endpoint limit is documented on its resource page.

Requesting limit increases

If your business genuinely needs more headroom (e.g., processing 50K transactions/day with a need for spiky read access), email hello@plugipay.com:

  • What workspace
  • What endpoints
  • Sustained vs peak rate you need
  • A brief description of your use case

We tune limits per-account based on stable usage history. For new accounts, we'd rather see a few days of traffic first — instant requests at sign-up are deferred.

Webhooks and rate limits

Webhooks (events Plugipay sends to you) are not limited on our side. We'll deliver as many as fire.

For your endpoint:

  • We time out at 10 seconds. If your handler takes longer, the delivery is marked failed and retried per the webhook retry policy.
  • If you're seeing 5xx or timeouts under load, queue events to a worker pool rather than processing inline.

Test mode for high-volume testing

Test mode has the same rate limits as live mode. If you're load-testing an integration, this matters — you can't get higher test-mode throughput without us raising your limits.

If you need temporary high test-mode limits for a load-testing window, let us know in advance — we can grant a 24-hour boost.

Common pitfalls

  • Setting retry parallelism without coordination. Two scripts each running 10-parallel adds up to 20 — over the write limit. Coordinate across scripts.
  • Treating 429 as a hard failure. It's transient. Always retry with backoff.
  • Ignoring X-RateLimit-Remaining. Watching it lets you slow down preemptively instead of recovering from 429s reactively.
  • Per-request retry of webhook DELIVERY (not endpoint call). We deliver webhooks; your endpoint's behavior under load is up to you.

Next

Plugipay — Payments that don't tax your success