Concepts
Rate limits
Limits keep one busy client from slowing everyone else down. Hitting one is never fatal: wait, then try again.
Every request counts against a limit per IP address. Requests with a key also draw on a
budget per key, and the endpoints that work without a key have tighter limits per IP of
their own. Over any of them the answer is 429 rate_limited, with a Retry-After header
giving the seconds to wait.
Handling a 429
Wait for the number of seconds in Retry-After, then send the same request again. Treat 503 the same way with a growing delay: a price feed or a node is briefly down. Send an idempotency_key on anything that moves money, so a retry can never act twice.
import time
import requests
def call(url, data, headers, attempts=5):
for attempt in range(attempts):
response = requests.post(url, data=data, headers=headers, timeout=30)
if response.status_code == 429:
time.sleep(int(response.headers.get("Retry-After", "5")))
elif response.status_code == 503:
time.sleep(2 ** attempt)
else:
return response
return responseconst sleep = (seconds) => new Promise((done) => setTimeout(done, seconds * 1000));
async function call(url, body, headers, attempts = 5) {
let response;
for (let attempt = 0; attempt < attempts; attempt++) {
response = await fetch(url, { method: "POST", headers, body });
if (response.status === 429) {
await sleep(Number(response.headers.get("Retry-After") ?? 5));
} else if (response.status === 503) {
await sleep(2 ** attempt);
} else {
break;
}
}
return response;
}function call(string $url, array $data, string $key, int $attempts = 5): ?array
{
for ($attempt = 0; $attempt < $attempts; $attempt++) {
$wait = 5;
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_HTTPHEADER => ["Authorization: Bearer $key"],
CURLOPT_POSTFIELDS => http_build_query($data),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADERFUNCTION => function ($ch, $line) use (&$wait) {
if (stripos($line, "Retry-After:") === 0) {
$wait = (int) trim(substr($line, 12));
}
return strlen($line);
},
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($status === 429) {
sleep($wait);
} elseif ($status === 503) {
sleep(2 ** $attempt);
} else {
return json_decode($body, true);
}
}
return null;
}