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);
}
}