Rate Limits

The PostCo API uses rate limiting to ensure reliable performance for all users by preventing any single integration from overwhelming the system. Understanding these limits helps you build resilient integrations that handle high-volume workflows smoothly.

Rate limits are applied per API key and per shop. When you exceed a rate limit, the API returns a 429 Too Many Requests status code. Your integration should handle this gracefully by implementing retry logic with exponential backoff.

Rate limit tiers

The PostCo API enforces rate limits at two levels: per API key and per shop. These limits ensure fair resource allocation while accommodating most integration use cases.

  • Name
    Per API key
    Description
    • 100 requests per minute — Short-term burst limit for rapid successive requests
    • 5,000 requests per hour — Sustained throughput limit for continuous operations
  • Name
    Per shop (aggregate)
    Description
    • 500 requests per minute — Combined limit across all API keys for your shop

    This aggregate limit ensures fair resource allocation across all shops, regardless of how many API keys each shop uses. All API keys for a shop share this limit, so multiple integrations count toward the same 500 requests per minute.

Understanding the two-tier system

Rate limits apply at both the API key level and the shop level simultaneously. Your requests must stay within both limits:

  • If you have one API key attempting to make 150 requests per minute, you'll hit the per-key limit at 100 requests, even though you're under the shop limit (500/min)
  • If you have 6 API keys each making 90 requests per minute, you'll hit the shop limit (540/min total) even though each key is under its individual limit (100/min)

This system allows multiple integrations while preventing any single integration or shop from consuming excessive resources.


Handling rate limit errors

When you exceed a rate limit, the API returns a 429 Too Many Requests status code with an error message.

Error response

When rate limited, the API returns this response:

429 error response

{
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limit_exceeded",
    "message": "Rate limit exceeded"
  }
}

Exponential backoff with jitter

The recommended approach for handling 429 errors is exponential backoff with jitter—wait progressively longer between retries, with randomization to prevent thundering herd problems.

Exponential backoff example

async function makeRequestWithRetry(url, options, maxRetries = 5) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch(url, options)

      if (response.status === 429) {
        // Calculate exponential backoff: 1s, 2s, 4s, 8s, 16s
        const baseDelay = Math.pow(2, attempt) * 1000
        // Add jitter: randomize between -25% and +25% of base delay
        const jitter = baseDelay * 0.25 * (Math.random() * 2 - 1)
        const delay = baseDelay + jitter

        console.log(`Rate limited. Retrying in ${Math.round(delay)}ms...`)
        await new Promise(resolve => setTimeout(resolve, delay))
        continue
      }

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`)
      }

      return await response.json()
    } catch (error) {
      if (attempt === maxRetries - 1) throw error
    }
  }
}

// Usage
const data = await makeRequestWithRetry(
  'https://360.postco.co/api/public/v1/return_orders',
  {
    headers: {
      'Authorization': 'Bearer sk_your_api_key_here'
    }
  }
)


Best practices

Follow these strategies to build integrations that stay within rate limits and handle throttling gracefully.

  • Name
    Implement exponential backoff
    Description

    Always retry 429 errors with increasing delays. The examples above show production-ready retry logic with jitter to prevent synchronized retries across multiple clients.

  • Name
    Respect rate limits proactively
    Description

    Design your integration to stay well under the limits. For example, fetching 1,000 return orders in 10 requests of 100 items spread over several minutes is better than making rapid-fire requests that hit the rate limit.

  • Name
    Use appropriate page sizes
    Description

    Larger page sizes (up to 100 items) reduce the number of requests needed. Fetching 1,000 return orders with limit=100 requires 10 requests instead of 20 with limit=50.

  • Name
    Cache responses when possible
    Description

    Store data locally and refresh periodically rather than fetching the same data repeatedly. Return order status doesn't change every second—polling every few minutes is usually sufficient.

  • Name
    Distribute requests over time
    Description

    If you're syncing large datasets daily, spread requests throughout the day rather than making all requests during a short window. This prevents hitting rate limits and reduces peak load.

  • Name
    Use filters to reduce data volume
    Description

    The status, submitted_at_min, and submitted_at_max parameters help you fetch only the data you need. Fetching only reviewed return orders from the past 24 hours requires fewer requests than fetching everything.

  • Name
    Monitor your usage patterns
    Description

    Track how many requests your integration makes over time. If you're consistently approaching the limits, consider optimizing your request patterns or spacing out operations.

  • Name
    Handle errors gracefully
    Description

    Don't retry non-transient errors (400, 401, 404). Only retry 429 and 5xx errors. Retrying a 401 Unauthorized error wastes rate limit quota and won't succeed.

  • Name
    Use separate API keys per integration
    Description

    Multiple API keys help isolate different systems. If one integration hits its per-key limit, others can continue operating at their own per-key limits, up to the aggregate shop limit of 500/min.


Common scenarios

High-volume data syncing

If you need to sync large datasets regularly:

  1. Batch your operations: Group requests and space them out over the hour
  2. Use incremental syncing: Use submitted_at_min to fetch only new/changed data since your last sync
  3. Implement checkpointing: Store the last cursor or timestamp to resume if interrupted
  4. Schedule during off-peak hours: Reduce contention with other integrations

Real-time monitoring

For integrations that monitor return orders in near-real-time:

  1. Poll, don't stream: Check for updates every 1-5 minutes, not every second
  2. Use narrow date filters: Query submitted_at_min with recent timestamps to minimize data
  3. Implement smart backoff: Reduce polling frequency when no new data appears

Note: Future webhook support will eliminate polling needs for real-time updates. Design your integration to support both polling and webhook-based updates for easier migration when webhooks become available.

Multiple parallel integrations

When running several systems that use the PostCo API:

  1. Assign separate API keys: Isolate each integration to track usage independently
  2. Coordinate request timing: Stagger requests so they don't all run simultaneously
  3. Share rate limit budget: Allocate portions of the 500/min shop limit to each integration
  4. Implement circuit breakers: If one integration hits limits repeatedly, pause it to let others operate

Troubleshooting rate limits

  • Name
    Constantly hitting rate limits
    Description

    Cause: Your integration makes too many requests in a short period.

    Solution:

    • Increase page size to limit=100 to reduce request count
    • Add delays between requests (e.g., 700ms delay = ~85 requests/min, staying under the 100/min limit)
    • Cache responses to reduce redundant requests
    • Use incremental syncing with date filters instead of fetching all data
  • Name
    Hitting shop limit with multiple keys
    Description

    Cause: Multiple API keys making concurrent requests exceed the 500/min shop limit.

    Solution:

    • Coordinate request timing across integrations
    • Use a shared rate limiter or queue to control aggregate request rate
    • Allocate rate limit budget (e.g., Integration A: 200/min, Integration B: 200/min, buffer: 100/min)
  • Name
    Exponential backoff takes too long
    Description

    Cause: Hitting rate limits too frequently, causing long retry delays.

    Solution:

    • Review why you're hitting rate limits frequently (see "Constantly hitting rate limits" above)
    • If retries are timing out, cap the maximum delay (e.g., max 32 seconds) and fail fast
    • Queue failed requests for retry during off-peak times
    • Consider if your use case truly needs synchronous responses, or if asynchronous processing is acceptable
  • Name
    Rate limits preventing time-sensitive operations
    Description

    Cause: Your integration requires higher throughput than current limits allow.

    Solution:

    • Contact PostCo support to discuss your use case
    • Higher limits may be available for enterprise plans
    • Consider architectural changes (batching, background processing, caching)

Need higher limits?

The current rate limits accommodate most integration patterns, including continuous monitoring, daily batch syncing, and multiple parallel workflows. If you've optimized your integration and still need higher throughput, we're happy to discuss your requirements—contact our support team at [email protected].

When requesting higher limits, please provide:

  • Description of your integration and use case
  • Current request volume and patterns
  • Expected request volume after optimization
  • Business justification for higher limits

Was this page helpful?