Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.propal.io/llms.txt

Use this file to discover all available pages before exploring further.

The Propal API uses a sliding window rate limiter. Each organization has a maximum number of requests allowed per hour. The window slides continuously with no fixed reset time.

Limits

Limit
Requests / hour1000
Rate limits apply per organization, not per API key. If you have multiple API keys for the same organization, they share the same limit.

Response headers

Every API response includes rate limit information in the headers:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 997
X-RateLimit-Reset: 1712178000
HeaderDescription
X-RateLimit-LimitMaximum requests allowed in the current window.
X-RateLimit-RemainingRequests remaining in the current window.
X-RateLimit-ResetUnix timestamp when the window resets.

When you’re rate limited

When you exceed your limit, the API returns a 429 Too Many Requests response:
{
  "error": {
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded."
  }
}
The response includes a Retry-After header indicating how many seconds to wait:
Retry-After: 3600

Best practices

1

Monitor your usage

Check X-RateLimit-Remaining in response headers. If it’s dropping fast, slow down your requests.
2

Use bulk operations

Fetch up to 100 items per request with limit=100 instead of making many small requests.
3

Cache responses

Cache API responses locally when the data doesn’t change frequently (e.g., templates, themes, organization details).
4

Implement backoff

When you receive a 429, wait for the Retry-After duration before retrying. Don’t retry immediately.
5

Spread requests over time

If you need to sync large amounts of data, spread your requests evenly over the hour rather than bursting them all at once.

Example: rate-limit-aware client

class PropalClient {
  constructor(apiKey) {
    this.apiKey = apiKey;
    this.remaining = Infinity;
  }

  async request(path, options = {}) {
    // Pre-check: if we know we're close to the limit, slow down
    if (this.remaining <= 5) {
      await new Promise(r => setTimeout(r, 1000));
    }

    const response = await fetch(`https://api.propal.io/v1${path}`, {
      ...options,
      headers: {
        'Authorization': `Bearer ${this.apiKey}`,
        'Content-Type': 'application/json',
        ...options.headers,
      },
    });

    // Update our local tracking
    this.remaining = parseInt(
      response.headers.get('X-RateLimit-Remaining') ?? '1000'
    );

    if (response.status === 429) {
      const retryAfter = parseInt(
        response.headers.get('Retry-After') ?? '60'
      );
      console.log(`Rate limited. Waiting ${retryAfter}s...`);
      await new Promise(r => setTimeout(r, retryAfter * 1000));
      return this.request(path, options); // Retry
    }

    return response;
  }
}

Need higher limits?

Contact us if you need higher rate limits for your organization.