Heartbeat

Copy & paste

Resilient code for 25 free APIs

Each snippet calls a working endpoint with a timeout sized from the 7-day latency we measured, retries on 5xx and 429 with exponential backoff and jitter, and fails fast on client errors. Timeouts update with the data: see how they are computed.

Open-Meteo Forecast Weathertimeout 3.5 s

p95 1047 ms, p99 1371 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 3500, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41&current=temperature_2m");

Python

import random, time, requests

def get(url, timeout=3.5, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41&current=temperature_2m")

curl

curl --max-time 3.5 --retry 2 --retry-delay 1 --retry-all-errors "https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41&current=temperature_2m"
Open-Meteo Geocoding Geocodingtimeout 2 s

p95 446 ms, p99 492 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 2000, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://geocoding-api.open-meteo.com/v1/search?name=Berlin&count=1");

Python

import random, time, requests

def get(url, timeout=2.0, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://geocoding-api.open-meteo.com/v1/search?name=Berlin&count=1")

curl

curl --max-time 2 --retry 2 --retry-delay 1 --retry-all-errors "https://geocoding-api.open-meteo.com/v1/search?name=Berlin&count=1"
OpenStreetMap Nominatim Geocodingtimeout 2 s

p95 544 ms, p99 628 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 2000, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://nominatim.openstreetmap.org/search?q=Berlin&format=json&limit=1");

Python

import random, time, requests

def get(url, timeout=2.0, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://nominatim.openstreetmap.org/search?q=Berlin&format=json&limit=1")

curl

curl --max-time 2 --retry 2 --retry-delay 1 --retry-all-errors "https://nominatim.openstreetmap.org/search?q=Berlin&format=json&limit=1"
Zippopotam.us Geocodingtimeout 2 s

p95 373 ms, p99 471 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 2000, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://api.zippopotam.us/us/90210");

Python

import random, time, requests

def get(url, timeout=2.0, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://api.zippopotam.us/us/90210")

curl

curl --max-time 2 --retry 2 --retry-delay 1 --retry-all-errors "https://api.zippopotam.us/us/90210"
Where the ISS at? Open datatimeout 4.5 s

p95 1463 ms, p99 1514 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 4500, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://api.wheretheiss.at/v1/satellites/25544");

Python

import random, time, requests

def get(url, timeout=4.5, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://api.wheretheiss.at/v1/satellites/25544")

curl

curl --max-time 4.5 --retry 2 --retry-delay 1 --retry-all-errors "https://api.wheretheiss.at/v1/satellites/25544"
World Bank Indicators Open datatimeout 2 s

p95 304 ms, p99 350 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 2000, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://api.worldbank.org/v2/country/br?format=json");

Python

import random, time, requests

def get(url, timeout=2.0, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://api.worldbank.org/v2/country/br?format=json")

curl

curl --max-time 2 --retry 2 --retry-delay 1 --retry-all-errors "https://api.worldbank.org/v2/country/br?format=json"
USGS Earthquakes Open datatimeout 2.5 s

p95 404 ms, p99 1074 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 2500, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_hour.geojson");

Python

import random, time, requests

def get(url, timeout=2.5, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_hour.geojson")

curl

curl --max-time 2.5 --retry 2 --retry-delay 1 --retry-all-errors "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_hour.geojson"
Nager.Date Holidays Open datatimeout 2 s

p95 236 ms, p99 320 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 2000, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://date.nager.at/api/v3/PublicHolidays/2026/US");

Python

import random, time, requests

def get(url, timeout=2.0, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://date.nager.at/api/v3/PublicHolidays/2026/US")

curl

curl --max-time 2 --retry 2 --retry-delay 1 --retry-all-errors "https://date.nager.at/api/v3/PublicHolidays/2026/US"
UK Carbon Intensity Open datatimeout 4.5 s

p95 1064 ms, p99 2015 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 4500, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://api.carbonintensity.org.uk/intensity");

Python

import random, time, requests

def get(url, timeout=4.5, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://api.carbonintensity.org.uk/intensity")

curl

curl --max-time 4.5 --retry 2 --retry-delay 1 --retry-all-errors "https://api.carbonintensity.org.uk/intensity"
Wikipedia REST Open datatimeout 2 s

p95 355 ms, p99 387 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 2000, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://en.wikipedia.org/api/rest_v1/page/summary/Earth");

Python

import random, time, requests

def get(url, timeout=2.0, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://en.wikipedia.org/api/rest_v1/page/summary/Earth")

curl

curl --max-time 2 --retry 2 --retry-delay 1 --retry-all-errors "https://en.wikipedia.org/api/rest_v1/page/summary/Earth"
Open Library Search Open datatimeout 16.5 s

p95 3627 ms, p99 8192 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 16500, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://openlibrary.org/search.json?q=dune&limit=1");

Python

import random, time, requests

def get(url, timeout=16.5, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://openlibrary.org/search.json?q=dune&limit=1")

curl

curl --max-time 16.5 --retry 2 --retry-delay 1 --retry-all-errors "https://openlibrary.org/search.json?q=dune&limit=1"
Coinbase Spot Price Cryptotimeout 2 s

p95 289 ms, p99 318 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 2000, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://api.coinbase.com/v2/prices/BTC-USD/spot");

Python

import random, time, requests

def get(url, timeout=2.0, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://api.coinbase.com/v2/prices/BTC-USD/spot")

curl

curl --max-time 2 --retry 2 --retry-delay 1 --retry-all-errors "https://api.coinbase.com/v2/prices/BTC-USD/spot"
CoinGecko Cryptotimeout 2 s

p95 219 ms, p99 297 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 2000, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd");

Python

import random, time, requests

def get(url, timeout=2.0, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd")

curl

curl --max-time 2 --retry 2 --retry-delay 1 --retry-all-errors "https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd"
Binance Ticker Cryptotimeout 2.5 s

p95 789 ms, p99 885 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 2500, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT");

Python

import random, time, requests

def get(url, timeout=2.5, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT")

curl

curl --max-time 2.5 --retry 2 --retry-delay 1 --retry-all-errors "https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT"
Frankfurter FX Financetimeout 8 s

p95 224 ms, p99 3804 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 8000, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://api.frankfurter.dev/v1/latest?base=USD&symbols=EUR");

Python

import random, time, requests

def get(url, timeout=8.0, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://api.frankfurter.dev/v1/latest?base=USD&symbols=EUR")

curl

curl --max-time 8 --retry 2 --retry-delay 1 --retry-all-errors "https://api.frankfurter.dev/v1/latest?base=USD&symbols=EUR"
ExchangeRate-API (open) Financetimeout 2 s

p95 189 ms, p99 267 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 2000, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://open.er-api.com/v6/latest/USD");

Python

import random, time, requests

def get(url, timeout=2.0, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://open.er-api.com/v6/latest/USD")

curl

curl --max-time 2 --retry 2 --retry-delay 1 --retry-all-errors "https://open.er-api.com/v6/latest/USD"
GitHub REST Dev toolstimeout 2 s

p95 463 ms, p99 535 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 2000, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://api.github.com/repos/torvalds/linux");

Python

import random, time, requests

def get(url, timeout=2.0, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://api.github.com/repos/torvalds/linux")

curl

curl --max-time 2 --retry 2 --retry-delay 1 --retry-all-errors "https://api.github.com/repos/torvalds/linux"
npm Registry Dev toolstimeout 5.5 s

p95 479 ms, p99 2614 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 5500, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://registry.npmjs.org/react/latest");

Python

import random, time, requests

def get(url, timeout=5.5, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://registry.npmjs.org/react/latest")

curl

curl --max-time 5.5 --retry 2 --retry-delay 1 --retry-all-errors "https://registry.npmjs.org/react/latest"
PyPI JSON Dev toolstimeout 2 s

p95 172 ms, p99 243 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 2000, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://pypi.org/pypi/requests/json");

Python

import random, time, requests

def get(url, timeout=2.0, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://pypi.org/pypi/requests/json")

curl

curl --max-time 2 --retry 2 --retry-delay 1 --retry-all-errors "https://pypi.org/pypi/requests/json"
httpbin Dev toolstimeout 8.5 s

p95 2733 ms, p99 3790 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 8500, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://httpbin.org/get");

Python

import random, time, requests

def get(url, timeout=8.5, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://httpbin.org/get")

curl

curl --max-time 8.5 --retry 2 --retry-delay 1 --retry-all-errors "https://httpbin.org/get"
JSONPlaceholder Dev toolstimeout 2 s

p95 182 ms, p99 260 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 2000, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://jsonplaceholder.typicode.com/todos/1");

Python

import random, time, requests

def get(url, timeout=2.0, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://jsonplaceholder.typicode.com/todos/1")

curl

curl --max-time 2 --retry 2 --retry-delay 1 --retry-all-errors "https://jsonplaceholder.typicode.com/todos/1"
Hacker News (Firebase) Dev toolstimeout 2 s

p95 507 ms, p99 557 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 2000, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://hacker-news.firebaseio.com/v0/topstories.json");

Python

import random, time, requests

def get(url, timeout=2.0, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://hacker-news.firebaseio.com/v0/topstories.json")

curl

curl --max-time 2 --retry 2 --retry-delay 1 --retry-all-errors "https://hacker-news.firebaseio.com/v0/topstories.json"
PokéAPI Fun & mediatimeout 2 s

p95 219 ms, p99 242 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 2000, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://pokeapi.co/api/v2/pokemon/ditto");

Python

import random, time, requests

def get(url, timeout=2.0, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://pokeapi.co/api/v2/pokemon/ditto")

curl

curl --max-time 2 --retry 2 --retry-delay 1 --retry-all-errors "https://pokeapi.co/api/v2/pokemon/ditto"
Dog CEO Fun & mediatimeout 2 s

p95 225 ms, p99 262 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 2000, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://dog.ceo/api/breeds/image/random");

Python

import random, time, requests

def get(url, timeout=2.0, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://dog.ceo/api/breeds/image/random")

curl

curl --max-time 2 --retry 2 --retry-delay 1 --retry-all-errors "https://dog.ceo/api/breeds/image/random"
Datamuse Words Fun & mediatimeout 2 s

p95 386 ms, p99 933 ms over 7 days. Endpoint: live status · official docs

JavaScript

async function get(url, {timeout = 2000, retries = 2} = {}) {
  for (let i = 0; i <= retries; i++) {
    try {
      const res = await fetch(url, { signal: AbortSignal.timeout(timeout) });
      if (res.ok) return await res.json();
      if (res.status < 500 && res.status !== 429) throw new Error(res.status);
    } catch (e) { if (i === retries) throw e; }
    await new Promise(r => setTimeout(r, 500 * 2 ** i + Math.random() * 1000)); // backoff + jitter
  }
}
const data = await get("https://api.datamuse.com/words?ml=ringing&max=3");

Python

import random, time, requests

def get(url, timeout=2.0, retries=2):
    for i in range(retries + 1):
        try:
            r = requests.get(url, timeout=timeout)
            if r.ok:
                return r.json()
            if r.status_code < 500 and r.status_code != 429:
                r.raise_for_status()
        except requests.RequestException:
            if i == retries:
                raise
        time.sleep(0.5 * 2 ** i + random.random())  # backoff + jitter

data = get("https://api.datamuse.com/words?ml=ringing&max=3")

curl

curl --max-time 2 --retry 2 --retry-delay 1 --retry-all-errors "https://api.datamuse.com/words?ml=ringing&max=3"