Skip to Content

Rate Limits

Penvio enforces rate limits to ensure fair usage and platform stability.

API access requires a Business plan or higher.

Exceeding rate limits will result in 429 Too Many Requests responses. Implement exponential backoff to handle rate limiting gracefully.

Overview

The E-Sign API has generous rate limits for Enterprise customers:

LimitValue
API Requests10,000 requests / 15 minutes

Rate limits are applied per API key.

Rate Limit Headers

All responses include rate limit information in headers:

HeaderDescription
X-RateLimit-LimitMaximum requests allowed in the window
X-RateLimit-RemainingRequests remaining in current window
X-RateLimit-ResetUnix timestamp when the window resets

Example headers:

X-RateLimit-Limit: 10000 X-RateLimit-Remaining: 9995 X-RateLimit-Reset: 1705331200

Rate Limit Exceeded

When you exceed the rate limit, you’ll receive a 429 Too Many Requests response:

{ "error": { "code": "RATE_LIMITED", "message": "Too many requests" } }

The X-RateLimit-Reset header tells you when you can retry.

Handling Rate Limits

Implement Exponential Backoff

async function fetchWithRetry(url, options, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { const response = await fetch(url, options); if (response.status !== 429) { return response; } const resetTime = response.headers.get('X-RateLimit-Reset'); const waitMs = resetTime ? (parseInt(resetTime) * 1000) - Date.now() : Math.pow(2, i) * 1000; await new Promise(resolve => setTimeout(resolve, Math.max(waitMs, 0))); } throw new Error('Rate limit exceeded after retries'); }

Monitor Usage

Check remaining requests before making calls:

async function checkRateLimit(apiKey) { const response = await fetch('https://penvio.io/api/v1/esign/templates', { method: 'HEAD', headers: { 'Authorization': `Bearer ${apiKey}` } }); const remaining = parseInt(response.headers.get('X-RateLimit-Remaining')); const reset = parseInt(response.headers.get('X-RateLimit-Reset')); return { remaining, reset }; }

Queue Requests

For batch operations, queue requests to stay under limits:

class RequestQueue { constructor(maxPerWindow = 10000, windowMs = 15 * 60 * 1000) { this.queue = []; this.requestCount = 0; this.windowStart = Date.now(); this.maxPerWindow = maxPerWindow; this.windowMs = windowMs; } async add(fn) { if (Date.now() - this.windowStart > this.windowMs) { this.requestCount = 0; this.windowStart = Date.now(); } if (this.requestCount >= this.maxPerWindow) { const waitTime = this.windowMs - (Date.now() - this.windowStart); await new Promise(resolve => setTimeout(resolve, waitTime)); this.requestCount = 0; this.windowStart = Date.now(); } this.requestCount++; return fn(); } } // Usage const queue = new RequestQueue(); for (const envelope of envelopes) { await queue.add(() => createEnvelope(envelope)); }

Custom Limits

Need higher rate limits? Contact your account manager or sales@penvio.io to discuss custom rate limits for high-volume use cases.

Best Practices

  1. Cache responses - Don’t fetch the same data repeatedly
  2. Use pagination efficiently - Request larger page sizes when possible
  3. Batch operations - Create envelopes in batches rather than one at a time
  4. Implement retry logic - Gracefully handle rate limits with exponential backoff
  5. Monitor usage - Track your API usage patterns and alert on anomalies

Next Steps

Last updated on