161 countries and territories138 of 193 UN membersmonthly to 2026-09back to 1926
Documentation / Guides / Limits and delivery / 25 of 26

Webhooks for new releases

Register an address and be told, signed, the moment a country's figures load, instead of polling.

Guide

On the Analyst and Intelligence plans, register an HTTPS address and we send it a signed POST each time a country's figures are loaded, instead of you polling /v1/releases. Up to five addresses per account, each for every country or a list of them.

Register, list, test, remove

curl -X POST "https://api.tourismapi.com/v1/webhooks" -H "X-API-Key: $TOURISM_API_KEY" \
  -H "Content-Type: application/json" -d '{"url": "https://example.com/hooks/tourism", "countries": ["ES", "TH"]}'

curl "https://api.tourismapi.com/v1/webhooks" -H "X-API-Key: $TOURISM_API_KEY"
curl -X POST "https://api.tourismapi.com/v1/webhooks/wh_7qk3m2xa/test" -H "X-API-Key: $TOURISM_API_KEY"
curl -X DELETE "https://api.tourismapi.com/v1/webhooks/wh_7qk3m2xa" -H "X-API-Key: $TOURISM_API_KEY"

Leave countries out for every country. The answer to the POST carries the webhook's secret once: keep it. GET /v1/webhooks/{id} shows the webhook and its last 20 deliveries. The address must be https:// on port 443 and reach the public internet.

The event

{
  "event": "release.loaded",
  "country": "CL",
  "to": "2026-08",
  "new": 45,
  "revised": 0,
  "at": "2026-10-12T12:01:11Z"
}

to is the country's newest period now. new counts the series loaded that reach that period when it moved on; revised counts the series whose figures changed for periods already held. A test sends "event": "release.test" with "country": "XX". Loads are checked every few minutes.

Checking the signature

Every delivery carries X-Signature: t=<unix seconds>,v1=<hex>, where the hex is HMAC-SHA256 of <t>.<raw body> with your secret. Also sent: X-Webhook-Id and X-Delivery-Id (the same id on every try of one delivery, so repeats can be ignored).

// PHP
[$t, $v1] = array_map(fn($x) => explode('=', $x, 2)[1], explode(',', $_SERVER['HTTP_X_SIGNATURE']));
$ok = hash_equals(hash_hmac('sha256', $t . '.' . file_get_contents('php://input'), $secret), $v1) && abs(time() - (int) $t) < 300;

# Python
t, v1 = [p.split('=', 1)[1] for p in request.headers['X-Signature'].split(',')]
ok = hmac.compare_digest(hmac.new(secret.encode(), f"{t}.".encode() + request.get_data(), 'sha256').hexdigest(), v1)

Retries

Answer with any 2xx within 10 seconds. Anything else is tried again after 5 minutes, 30 minutes, 2 hours, 6 hours and 12 hours (about a day in all), then given up. An address that fails 20 deliveries in a row is switched off; its status says so when listed, and registering it again starts it afresh. Redirects are not followed.