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=100requires 10 requests instead of 20 withlimit=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, andsubmitted_at_maxparameters help you fetch only the data you need. Fetching onlyreviewedreturn 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:
- Batch your operations: Group requests and space them out over the hour
- Use incremental syncing: Use
submitted_at_minto fetch only new/changed data since your last sync - Implement checkpointing: Store the last cursor or timestamp to resume if interrupted
- Schedule during off-peak hours: Reduce contention with other integrations
Real-time monitoring
For integrations that monitor return orders in near-real-time:
- Poll, don't stream: Check for updates every 1-5 minutes, not every second
- Use narrow date filters: Query
submitted_at_minwith recent timestamps to minimize data - 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:
- Assign separate API keys: Isolate each integration to track usage independently
- Coordinate request timing: Stagger requests so they don't all run simultaneously
- Share rate limit budget: Allocate portions of the 500/min shop limit to each integration
- 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=100to 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
- Increase page size to
- 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