Overview
Mangopay implements rate limiting to ensure API stability and fair usage across all clients. Rate limits restrict the number of API calls you can make within specific time windows.Rate Limit Windows
Mangopay tracks API calls across four time windows:- Last 15 minutes
- Last 30 minutes
- Last 60 minutes
- Last 24 hours
Checking Rate Limits
After any API call, you can check your current rate limit status:require_once 'vendor/autoload.php';
$api = new MangoPay\MangoPayApi();
$api->Config->ClientId = 'your-client-id';
$api->Config->ClientPassword = 'your-client-password';
$api->Config->TemporaryFolder = '/tmp/';
// Make an API call
try {
$users = $api->Users->GetAll();
// Check rate limits after the call
$rateLimits = $api->RateLimits;
// RateLimits is an array of 4 RateLimit objects
// [0] = 15 minutes
// [1] = 30 minutes
// [2] = 60 minutes
// [3] = 24 hours
echo "15-minute window:\n";
echo " Calls made: " . $rateLimits[0]->CallsMade . "\n";
echo " Calls remaining: " . $rateLimits[0]->CallsRemaining . "\n";
echo " Reset at: " . date('Y-m-d H:i:s', $rateLimits[0]->ResetTimeTimestamp) . "\n\n";
echo "60-minute window:\n";
echo " Calls made: " . $rateLimits[2]->CallsMade . "\n";
echo " Calls remaining: " . $rateLimits[2]->CallsRemaining . "\n";
echo " Reset at: " . date('Y-m-d H:i:s', $rateLimits[2]->ResetTimeTimestamp) . "\n";
} catch (MangoPay\Libraries\ResponseException $e) {
echo "Error: " . $e->GetMessage();
}
Complete Rate Limit Monitoring
Monitor all time windows:function displayRateLimits($api) {
$rateLimits = $api->RateLimits;
$windows = [
0 => '15 minutes',
1 => '30 minutes',
2 => '60 minutes',
3 => '24 hours'
];
foreach ($windows as $index => $windowName) {
$limit = $rateLimits[$index];
echo "Rate limit for {$windowName}:\n";
echo " Calls made: {$limit->CallsMade}\n";
echo " Calls remaining: {$limit->CallsRemaining}\n";
echo " Resets at: " . date('H:i:s', $limit->ResetTimeTimestamp) . "\n";
// Calculate percentage used
$total = $limit->CallsMade + $limit->CallsRemaining;
$percentage = ($limit->CallsMade / $total) * 100;
echo " Usage: " . number_format($percentage, 1) . "%\n\n";
}
}
// Usage
try {
$api->Users->Get($userId);
displayRateLimits($api);
} catch (MangoPay\Libraries\ResponseException $e) {
echo "Error: " . $e->GetMessage();
}
Handling Rate Limit Exceeded
When you exceed rate limits, Mangopay returns a 429 status code:function makeApiCallWithRetry($api, $callable, $maxRetries = 3) {
$retries = 0;
while ($retries < $maxRetries) {
try {
$result = $callable($api);
return $result;
} catch (MangoPay\Libraries\ResponseException $e) {
// Check if rate limit exceeded
if ($e->GetCode() === 429) {
$rateLimits = $api->RateLimits;
// Find the window with least remaining time
$minResetTime = PHP_INT_MAX;
foreach ($rateLimits as $limit) {
if ($limit->CallsRemaining === 0) {
$resetTime = $limit->ResetTimeTimestamp - time();
$minResetTime = min($minResetTime, $resetTime);
}
}
if ($minResetTime > 0 && $minResetTime < 900) { // Max 15 min wait
echo "Rate limit exceeded. Waiting {$minResetTime} seconds...\n";
sleep($minResetTime + 1);
$retries++;
} else {
throw $e;
}
} else {
throw $e;
}
}
}
throw new Exception('Max retries exceeded');
}
// Usage
try {
$result = makeApiCallWithRetry($api, function($api) use ($userId) {
return $api->Users->Get($userId);
});
echo "User retrieved successfully";
} catch (Exception $e) {
echo "Error: " . $e->getMessage();
}
Proactive Rate Limit Management
Check limits before making calls:function canMakeApiCall($api, $threshold = 0.1) {
$rateLimits = $api->RateLimits;
// Check if any window is close to limit
foreach ($rateLimits as $limit) {
$total = $limit->CallsMade + $limit->CallsRemaining;
$remaining = $limit->CallsRemaining;
// If less than threshold (10%) remaining
if ($remaining / $total < $threshold) {
return false;
}
}
return true;
}
// Usage
if (canMakeApiCall($api, 0.1)) {
$user = $api->Users->Get($userId);
} else {
echo "Approaching rate limit. Waiting before next call...";
sleep(60);
}
Batch Processing with Rate Limits
Process items in batches while respecting rate limits:function processBatchWithRateLimits($api, $items, $processor) {
$processed = [];
$failed = [];
foreach ($items as $item) {
// Check rate limits
$rateLimits = $api->RateLimits;
$shouldWait = false;
$waitTime = 0;
// Check if any window is at 90% capacity
foreach ($rateLimits as $limit) {
$total = $limit->CallsMade + $limit->CallsRemaining;
if ($limit->CallsRemaining < $total * 0.1) {
$shouldWait = true;
$waitTime = max($waitTime, $limit->ResetTimeTimestamp - time());
}
}
if ($shouldWait && $waitTime > 0) {
echo "Approaching rate limit. Waiting {$waitTime} seconds...\n";
sleep($waitTime + 1);
}
try {
$result = $processor($api, $item);
$processed[] = [
'item' => $item,
'result' => $result
];
} catch (MangoPay\Libraries\ResponseException $e) {
$failed[] = [
'item' => $item,
'error' => $e->GetMessage()
];
}
// Small delay between requests
usleep(100000); // 100ms
}
return [
'processed' => $processed,
'failed' => $failed
];
}
// Usage
$userIds = ['user_1', 'user_2', 'user_3', /* ... */];
$results = processBatchWithRateLimits($api, $userIds, function($api, $userId) {
return $api->Users->Get($userId);
});
echo "Processed: " . count($results['processed']) . "\n";
echo "Failed: " . count($results['failed']);
Rate Limit Dashboard
Create a monitoring dashboard:class RateLimitMonitor {
private $api;
public function __construct($api) {
$this->api = $api;
}
public function getStatus() {
$rateLimits = $this->api->RateLimits;
return [
'15min' => $this->getLimitInfo($rateLimits[0]),
'30min' => $this->getLimitInfo($rateLimits[1]),
'60min' => $this->getLimitInfo($rateLimits[2]),
'24hours' => $this->getLimitInfo($rateLimits[3])
];
}
private function getLimitInfo($limit) {
$total = $limit->CallsMade + $limit->CallsRemaining;
$percentage = ($limit->CallsMade / $total) * 100;
return [
'calls_made' => $limit->CallsMade,
'calls_remaining' => $limit->CallsRemaining,
'percentage_used' => round($percentage, 2),
'reset_at' => date('Y-m-d H:i:s', $limit->ResetTimeTimestamp),
'seconds_until_reset' => $limit->ResetTimeTimestamp - time()
];
}
public function getHealth() {
$status = $this->getStatus();
foreach ($status as $window => $info) {
if ($info['percentage_used'] > 90) {
return 'critical';
} elseif ($info['percentage_used'] > 75) {
return 'warning';
}
}
return 'healthy';
}
public function displayStatus() {
$status = $this->getStatus();
foreach ($status as $window => $info) {
$bar = $this->createProgressBar($info['percentage_used']);
echo "{$window}:\n";
echo " {$bar} {$info['percentage_used']}%\n";
echo " {$info['calls_made']} / " .
($info['calls_made'] + $info['calls_remaining']) . " calls\n";
echo " Resets in {$info['seconds_until_reset']} seconds\n\n";
}
echo "Overall health: " . strtoupper($this->getHealth()) . "\n";
}
private function createProgressBar($percentage, $length = 40) {
$filled = round(($percentage / 100) * $length);
$empty = $length - $filled;
return '[' . str_repeat('=', $filled) . str_repeat(' ', $empty) . ']';
}
}
// Usage
$monitor = new RateLimitMonitor($api);
// Make some API calls
$api->Users->Get($userId);
// Display status
$monitor->displayStatus();
Best Practices
Check Before Batch
Always check rate limits before processing large batches.
Implement Backoff
Use exponential backoff when approaching limits.
Cache Data
Cache frequently accessed data to reduce API calls.
Monitor Usage
Track rate limit usage over time to optimize performance.
Optimization Strategies
1. Use Pagination Efficiently
Request more items per page to reduce total calls:// Less efficient: 10 calls for 100 items
$pagination = new MangoPay\Pagination(1, 10);
// More efficient: 1 call for 100 items
$pagination = new MangoPay\Pagination(1, 100);
$users = $api->Users->GetAll($pagination);
2. Cache Frequently Accessed Data
class CachedMangopayClient {
private $api;
private $cache = [];
private $cacheTTL = 300; // 5 minutes
public function __construct($api) {
$this->api = $api;
}
public function getUser($userId) {
$cacheKey = "user_{$userId}";
// Check cache
if (isset($this->cache[$cacheKey])) {
$cached = $this->cache[$cacheKey];
if (time() - $cached['time'] < $this->cacheTTL) {
return $cached['data'];
}
}
// Fetch from API
$user = $this->api->Users->Get($userId);
// Cache result
$this->cache[$cacheKey] = [
'data' => $user,
'time' => time()
];
return $user;
}
}
$client = new CachedMangopayClient($api);
// First call hits API
$user = $client->getUser($userId);
// Subsequent calls within 5 minutes use cache
$user = $client->getUser($userId); // No API call
3. Batch Operations When Possible
Group related operations:// Instead of multiple individual calls
foreach ($userIds as $userId) {
$user = $api->Users->Get($userId); // Many API calls
}
// Use GetAll with filtering
$pagination = new MangoPay\Pagination(1, 100);
$allUsers = $api->Users->GetAll($pagination); // One API call
Rate Limit Alerts
Set up alerts when approaching limits:function checkRateLimitAlert($api, $thresholds = [80, 90, 95]) {
$rateLimits = $api->RateLimits;
$alerts = [];
$windows = ['15 minutes', '30 minutes', '60 minutes', '24 hours'];
foreach ($rateLimits as $index => $limit) {
$total = $limit->CallsMade + $limit->CallsRemaining;
$percentage = ($limit->CallsMade / $total) * 100;
foreach ($thresholds as $threshold) {
if ($percentage >= $threshold) {
$alerts[] = [
'window' => $windows[$index],
'percentage' => round($percentage, 2),
'level' => $threshold >= 95 ? 'critical' :
($threshold >= 90 ? 'warning' : 'info'),
'reset_in' => $limit->ResetTimeTimestamp - time()
];
break;
}
}
}
return $alerts;
}
// Check after API calls
$api->Users->Get($userId);
$alerts = checkRateLimitAlert($api);
foreach ($alerts as $alert) {
error_log(
"RATE LIMIT {$alert['level']}: " .
"{$alert['window']} window at {$alert['percentage']}% " .
"(resets in {$alert['reset_in']}s)"
);
}
Error Handling
Comprehensive error handling for rate limits:try {
$result = $api->Users->Get($userId);
} catch (MangoPay\Libraries\ResponseException $e) {
if ($e->GetCode() === 429) {
// Rate limit exceeded
$rateLimits = $api->RateLimits;
error_log('Rate limit exceeded!');
error_log('15-min calls remaining: ' . $rateLimits[0]->CallsRemaining);
error_log('60-min calls remaining: ' . $rateLimits[2]->CallsRemaining);
// Calculate wait time
$waitTime = 0;
foreach ($rateLimits as $limit) {
if ($limit->CallsRemaining === 0) {
$resetTime = $limit->ResetTimeTimestamp - time();
$waitTime = max($waitTime, $resetTime);
}
}
throw new Exception("Rate limit exceeded. Retry in {$waitTime} seconds");
} else {
throw $e;
}
}
Testing Rate Limits
Test your rate limit handling:function testRateLimitHandling($api) {
$callCount = 0;
$startTime = time();
try {
// Make rapid API calls
while (true) {
$api->Users->GetAll(new MangoPay\Pagination(1, 1));
$callCount++;
$rateLimits = $api->RateLimits;
echo "Call #{$callCount}: " .
"{$rateLimits[0]->CallsRemaining} remaining in 15-min window\n";
// Stop if we hit the limit
if ($rateLimits[0]->CallsRemaining < 5) {
echo "Approaching limit. Stopping test.\n";
break;
}
}
} catch (MangoPay\Libraries\ResponseException $e) {
if ($e->GetCode() === 429) {
echo "Rate limit hit after {$callCount} calls in " .
(time() - $startTime) . " seconds\n";
}
}
}
Next Steps
Webhooks
Reduce polling by using webhooks
API Reference
View complete API documentation