Rate limit | API 3.0
docs.sportmonks.comCopy
<?php
class RateLimiter {
private $maxRequests;
private $windowSeconds;
private $requests = [];
public function __construct($maxRequests = 3000, $windowSeconds = 3600) {
$this->maxRequests = $maxRequests;
$this->windowSeconds = $windowSeconds;
}
public function throttle($entity = 'default') {
$now = time();
// Initialise entity if needed
if (!isset($this->requests[$entity])) {
$this->requests[$entity] = [];
}
// Remove old requests outside the window
$this->requests[$entity] = array_filter(
$this->requests[$entity],
function($timestamp) use ($now) {
return ($now - $timestamp) < $this->windowSeconds;
}
);
// Check if at limit
if (count($this->requests[$entity]) >= $this->maxRequests) {
$oldestRequest = min($this->requests[$entity]);
$waitTime = $this->windowSeconds - ($now - $oldestRequest);
echo "Throttling {$entity}: waiting {$waitTime}s\n";
sleep($waitTime);
// Try again recursively
return $this->throttle($entity);
}
// Add this request to history
$this->requests[$entity][] = $now;
}
}
class SportmonksAPI {
private $token;
private $baseUrl = 'https://api.sportmonks.com/v3/football';
private $cache = [];
private $limiter;
public function __construct($apiToken, $maxRequests = 2800) {
$this->token = $apiToken;
$this->limiter = new RateLimiter($maxRequests);
}
public function request($endpoint, $params = [], $entity = 'default', $maxRetries = 3) {
// Throttle request
$this->limiter->throttle($entity);
// Build URL
$params['api_token'] = $this->token;
$url = $this->baseUrl . $endpoint . '?' . http_build_query($params);
// Make request with retry logic
for ($attempt = 0; $attempt < $maxRetries; $attempt++) {
try {
$response = $this->fetchWithRetry($url, $attempt);
$data = json_decode($response, true);
// Log rate limit info
if (isset($data['rate_limit'])) {
$this->logRateLimit($data['rate_limit']);
}
return $data;
} catch (Exception $e) {
if ($attempt === $maxRetries - 1) {
throw $e;
}
// Exponential backoff
$waitTime = pow(2, $attempt);
echo "Request failed. Retrying after {$waitTime}s...\n";
sleep($waitTime);
}
}
}
private function fetchWithRetry($url, $attempt) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode === 429) {
$data = json_decode($response, true);
$retryAfter = $data['retry_after'] ?? pow(2, $attempt);
echo "Rate limited. Retrying after {$retryAfter}s...\n";
sleep($retryAfter);
// Retry recursively
return $this->fetchWithRetry($url, $attempt);
}
if ($httpCode !== 200) {
throw new Exception("HTTP {$httpCode}: {$response}");
}
return $response;
}
private function logRateLimit($rateLimit) {
$remaining = $rateLimit['remaining'] ?? '?';
$entity = $rateLimit['requested_entity'] ?? 'Unknown';
echo "{$entity}: {$remaining} requests remaining\n";
if ($remaining < 200) {
echo "⚠️ Low on {$entity} requests! Optimize your calls.\n";
}
}
// Cached method for types
public function getTypes() {
$cacheKey = 'types';
$cacheDuration = 7 * 24 * 60 * 60; // 1 week
if (isset($this->cache[$cacheKey])) {
$cached = $this->cache[$cacheKey];
if (time() - $cached['timestamp'] < $cacheDuration) {
echo "Using cached types\n";
return $cached['data'];
}
}
echo "Fetching fresh types\n";
$response = $this->request('/core/types', [], 'Type');
$this->cache[$cacheKey] = [
'data' => $response['data'],
'timestamp' => time()
];
return $response['data'];
}
// Helper method for batched requests
public function getFixturesByIds($ids) {
if (empty($ids)) {
return [];
}
$idsString = implode(',', $ids);
return $this->request("/fixtures/multi/{$idsString}", [], 'Fixture');
}
}
// Usage Example
try {
$api = new SportmonksAPI('YOUR_TOKEN_HERE');
// Single fixture with includes
$fixture = $api->request('/fixtures/123', [
'include' => 'participants;scores;events'
], 'Fixture');
echo "Fixture: {$fixture['data']['name']}\n";
// Batched request
$multipleFixtures = $api->getFixturesByIds([123, 456, 789]);
echo "Fetched " . count($multipleFixtures['data']) . " fixtures\n";
// Cached types (only fetches once)
$types = $api->getTypes();
echo "Got " . count($types) . " types\n";
// Types from cache (0 API calls)
$typesAgain = $api->getTypes();
} catch (Exception $e) {
echo "Error: " . $e->getMessage() . "\n";
}
?>