Rate limit best practices
This page covers techniques for avoiding rate limits, tracking your API usage, requesting a limit increase, and handling 429 responses. For the rate limit table and categories, see Rate limits.
Use exponential backoff
Exponential backoff is a technique used to prevent overwhelming a server with too many requests in a short period of time. It involves progressively increasing the delay between retries when encountering rate limits or server errors.
To implement exponential backoff, you can follow these steps:
- Define a base delay: Start with a small delay, such as 1 second, as the base delay for the first retry.
- Define a maximum number of retries: Determine the maximum number of retries you want to attempt before giving up.
- Implement retry logic: Wrap your API request code in a retry loop that will retry the request if it encounters a rate limit or server error.
- Calculate the delay: Use an exponential function to calculate the delay for each retry. The delay can be calculated using the formula:
delay=baseDelay* (2 ^retryCount), whereretryCountstarts from 0 for the first retry. - Apply the delay: Before each retry, pause the execution of the code for the calculated delay duration.
Here's are examples of how you can implement exponential backoff:
- Python
- Javascript
Python exponential backoff example (click to expand)
import time
base_delay = 1 # 1 second
max_retries = 5
max_delay = 32
def make_api_request():
# Your API request code goes here
pass
def retry_with_exponential_backoff():
attempt = 0
delay = base_delay
while attempt < max_retries:
try:
result = make_api_request()
return result
except Exception as e:
attempt += 1
if attempt >= max_retries:
raise e
sleep_time = min(delay * (2 ** attempt), max_delay)
print(f"Attempt {attempt} failed. Retrying in {sleep_time:.2f} seconds...")
time.sleep(sleep_time)
raise Exception("All retry attempts failed.")
retry_with_exponential_backoff()
Javascript exponential backoff example (click to expand)
const baseDelay = 1000; // 1 second
const maxRetries = 5;
let retryCount = 0;
function makeApiRequest() {
// Your API request code goes here
}
function retryWithExponentialBackoff() {
if (retryCount < maxRetries) {
const delay = baseDelay * Math.pow(2, retryCount);
setTimeout(() => {
retryCount++;
makeApiRequest();
}, delay);
} else {
console.log('Exceeded maximum retries');
}
}
retryWithExponentialBackoff();
In this example, the makeApiRequest function represents your actual API request code. The retryWithExponentialBackoff function is responsible for calculating the delay and retrying the request using exponential backoff. It uses the setTimeout function to pause the execution for the calculated delay duration. Remember to adjust the baseDelay and maxRetries values according to your specific requirements.
Exponential backoff helps to distribute the load on the server and increases the chances of a successful request without exceeding rate limits.
Use bulk operations
When creating or updating multiple entities, use bulk endpoints instead of individual requests. This reduces the number of API calls and helps you stay within rate limits.
| Operation | Single request endpoint | Bulk endpoint | Benefit |
|---|---|---|---|
| Create entities | POST /v1/blueprints/{id}/entities | POST /v1/blueprints/{id}/entities/bulk | Create up to 100 entities per request. |
| Update entities | PATCH /v1/blueprints/{id}/entities/{entity_id} | POST /v1/blueprints/{id}/entities/bulk with upsert=true | Update multiple entities in one call. |
| Delete entities | DELETE /v1/blueprints/{id}/entities/{entity_id} | POST /v1/blueprints/{id}/bulk/entities/delete | Delete up to 100 entities per request. |
Track your API usage
To understand your current API consumption patterns:
Check headers on each response
Every API response includes rate limit headers. Build monitoring around these:
Check rate limit headers example (click to expand)
import requests
response = requests.get(
"https://api.getport.io/v1/blueprints",
headers={"Authorization": f"Bearer {access_token}"}
)
remaining = response.headers.get("x-ratelimit-remaining")
limit = response.headers.get("x-ratelimit-limit")
reset_seconds = response.headers.get("x-ratelimit-reset")
print(f"Requests remaining: {remaining}/{limit}")
print(f"Resets in: {reset_seconds} seconds")
if int(remaining) < 100:
print("Warning: approaching rate limit")
Log rate limit metrics
For production workloads, consider logging rate limit headers to track usage patterns over time:
Log rate limit metrics example (click to expand)
import logging
def log_rate_limits(response, operation_name):
logging.info(
"Rate limit status",
extra={
"operation": operation_name,
"remaining": response.headers.get("x-ratelimit-remaining"),
"limit": response.headers.get("x-ratelimit-limit"),
"reset": response.headers.get("x-ratelimit-reset"),
}
)
Calculate your request budget
To plan for scale, estimate your request needs:
| Use case | Calculation | Example |
|---|---|---|
| Integration resyncs | (entities per resync) × (resyncs per hour) × 12 | 1,000 entities × 1 resync/hour × 12 = 12,000 requests per 5 min window. |
| CI/CD updates | (deployments per hour) × (entities updated per deploy) × 12 | 10 deploys × 5 entities × 12 = 600 requests per 5 min window. |
| Automation actions | (action runs per hour) × (API calls per action) × 12 | 50 runs × 3 calls × 12 = 1,800 requests per 5 min window. |
Add up your use cases and compare against the limits in the rate limits table.
Request a limit increase
If your workload requires higher rate limits:
-
Optimize first: Review your usage patterns. Can you use bulk endpoints? Reduce polling frequency? Cache results?
-
Document your needs: Prepare details about:
- Your current request volume.
- Expected growth trajectory.
- Which endpoints are hitting limits.
- Why higher limits are necessary for your use case.
-
Contact Port support: Reach out to Port support with your documentation. Include:
- Your organization ID.
- The specific rate limit categories you need increased.
- Your expected request volume.
Rate limit increases are evaluated on a case-by-case basis and may require an enterprise plan.
Handling 429 responses
When you exceed rate limits, the API returns a 429 Too Many Requests response. Handle this gracefully:
Handling 429 responses example (click to expand)
import time
import requests
def make_request_with_retry(url, headers, max_retries=5):
for attempt in range(max_retries):
response = requests.get(url, headers=headers)
if response.status_code == 429:
reset_seconds = int(response.headers.get("x-ratelimit-reset", 60))
print(f"Rate limited. Waiting {reset_seconds} seconds...")
time.sleep(reset_seconds)
continue
response.raise_for_status()
return response
raise Exception("Max retries exceeded due to rate limiting")
When rate limited, use the x-ratelimit-reset header to know exactly when you can resume requests, rather than guessing with arbitrary delays.