Skip to main content

Working with API Rate Limits

Improve API reliability with smart rate limit handling

Updated this week

Overview

You may encounter 429 Too Many Requests errors when you hit an API rate limit. This can happen in two scenarios:

  • Monthly billing limits - based on your subscription plan:

    • Plans with an overage allowance will apply additional charges when you go beyond your plan limits.

    • Plans without overage allowance will block API calls when limits are reached.

NOTE: Standard iPaaS.com plans do not have monthly billing limits.

  • Volume restrictions occur when API resources are overwhelmed by high request volume.

Example: Handling API Rate Limits

This example demonstrates how to handle HTTP 429 Too Many Requests as a result of hitting rate limits. Adapt this approach for your integration's API.

Logic Flow

Design Decisions

Our implementation uses these principles:

  • 60-second threshold: Implemented to avoid exceeding request limits on the system.

  • Automatic retry vs failure: Balances user experience with system performance.

  • Dual logging: Provides both user-friendly messages and technical details.

  • Cancellation support: Allows interrupting the wait period if needed.

Implementation

This example uses the Shopify API. Modify the code for your integration.

// Check if the API response indicates we've hit the rate limit
if (resp.StatusCode == System.Net.HttpStatusCode.TooManyRequests)
{
// Extract the "Retry-After" header which tells us how long to wait before trying again
var retryAfter = ReadResponseHeader(resp, "Retry-After");

// Parse the retry time (usually in seconds) and store it in our response object
double.TryParse(retryAfter, out apiResponse.LimitTimeResetSeconds);

// Shopify's API allocates requests per minute, so reset time should be under 60 seconds
// If it's reasonable (< 60 seconds), we'll wait and retry automatically
// If it's longer, we'll give up and throw an error instead of waiting too long
if (apiResponse.LimitTimeResetSeconds < 60)
{
// Build a technical error message for logging
var techErr = $"Received TooManyRequests response from Shopify. The call was rejected, but we will wait for more calls to be available in {apiResponse.LimitTimeResetSeconds} seconds";

// Include response details if available
if (resp.Content != null)
techErr += $". Details: {resp.Content}";

// Log a user-friendly activity message (Warning level)
connection.Logger.LogActivityTracker(
"Failed API Call to Shopify (Quota)",
$"Received TooManyRequests response from {actionCustomerFacing}. You are over your API quota but we will wait for more calls to be available in {apiResponse.LimitTimeResetSeconds} seconds",
"Warning",
(int)mappingCollectionType
);

// Log technical details for developers/debugging
connection.Logger.LogTechnical(
"D", // Debug level
$"ShopifyCallWrapper.{action}",
techErr
);

// Wait for the specified number of seconds (convert to milliseconds)
// Uses a cancellation-aware sleep method
await StandardUtilities.SleepWithCancelSupport(Convert.ToInt16(apiResponse.LimitTimeResetSeconds) * 1000);

// Tell the calling code to retry this request
apiResponse.action = IntegrationAPIResponse.ResponseAction.Retry;
return apiResponse;
}
else
{
// If the wait time is too long (>= 60 seconds), don't wait - just fail

// Create a response object and copy quota information
var response = new Integration.Abstract.Model.ResponseObject();
StandardUtilities.AssignQuotaValues(response, apiResponse);

// Log an error-level activity message for the user
connection.Logger.LogActivityTracker(
"Failed API Call to Shopify (Quota)",
$"Received TooManyRequests response from {actionCustomerFacing}. You are over your API quota but more calls should be available in {apiResponse.LimitTimeResetSeconds} seconds",
"Error",
(int)mappingCollectionType
);

// Log technical error details
connection.Logger.LogTechnical(
"E", // Error level
$"ShopifyCallWrapper.{action}",
$"Too many API calls made to Shopify. The call was rejected. Most calls should be available in {apiResponse.LimitTimeResetSeconds} seconds"
);

// Throw an exception to stop processing
throw new Exception("Shopify API Quota Exception. Too Many Requests. Available in: " + apiResponse.LimitTimeResetSeconds);
}
}
Did this answer your question?