Webhooks for Country Data Changes — Get Notified When ISO Codes Update
Most apps using country / state / city data cache it locally for performance. The downside: when a country splits, an ISO code changes, or a state gets renamed, your cache goes stale until the next manual refresh.
ApogeoAPI's webhook system pushes those events to your endpoint as soon as the underlying data changes. This tutorial covers the full setup with HMAC signature verification.
Available events
| Event | Fired when |
|---|---|
country.created | A new country is added to the database (rare — average ~1/year) |
country.updated | Any field on a country changes (capital, currency, name, region) |
country.deleted | A country is removed (extremely rare) |
state.updated | A state/province record changes |
currency_rate.updated | Live FX refresh — fires every 4 hours per currency |
Register the webhook
From your dashboard at app.apogeoapi.com → Webhooks → Add endpoint. Paste your URL, choose which events to subscribe to, and copy the secret. Or via API:
curl -X POST https://api.apogeoapi.com/v1/webhooks \
-H "X-API-Key: $APOGEOAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.com/webhooks/apogeoapi",
"events": ["country.updated", "state.updated"],
"active": true
}'
Response includes a secret field — save it; you'll need it to verify signatures.
Receive + verify in Node.js / Express
import express from 'express';
import crypto from 'node:crypto';
const app = express();
const SECRET = process.env.APOGEO_WEBHOOK_SECRET!;
// IMPORTANT: webhook handlers need the RAW body to verify the HMAC.
// Use express.raw() instead of express.json().
app.post(
'/webhooks/apogeoapi',
express.raw({ type: 'application/json' }),
(req, res) => {
const signature = req.header('X-ApogeoAPI-Signature');
if (!signature) return res.status(400).send('missing signature');
const expected = crypto
.createHmac('sha256', SECRET)
.update(req.body)
.digest('hex');
if (
!crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
)
) {
return res.status(401).send('invalid signature');
}
const event = JSON.parse(req.body.toString('utf8'));
handleEvent(event);
res.status(204).end();
}
);
interface Event {
id: string;
event: string;
data: Record;
occurredAt: string;
}
function handleEvent(event: Event) {
switch (event.event) {
case 'country.updated':
console.log('Country changed:', event.data);
// invalidateCache(event.data.iso2)
break;
case 'currency_rate.updated':
// updateLocalRate(event.data.currency, event.data.usdRate)
break;
}
}
Payload examples
country.updated
{
"id": "evt_2026_03_27_abc123",
"event": "country.updated",
"data": {
"iso2": "TR",
"name": "Türkiye",
"previousName": "Turkey",
"changedFields": ["name", "translations"]
},
"occurredAt": "2026-03-27T14:32:11Z"
}
currency_rate.updated
{
"id": "evt_2026_03_27_def456",
"event": "currency_rate.updated",
"data": {
"currency": "ARS",
"usdRate": 1480.5,
"previousUsdRate": 1450.2,
"lastUpdated": "2026-03-27T14:00:00Z"
},
"occurredAt": "2026-03-27T14:00:03Z"
}
Retry behavior
If your endpoint returns non-2xx, ApogeoAPI retries with exponential backoff: 1 min, 5 min, 30 min, 2h, 8h. After 5 failed attempts, the webhook is marked inactive and an email is sent to your account address.
To handle retries idempotently, key your local processing on the id field. ApogeoAPI guarantees the same id for retries of the same event.
Testing locally
Use ngrok or Cloudflare Tunnel to expose your localhost endpoint, register that URL as the webhook target, and trigger test events from the dashboard's "Send test event" button.
What we don't deliver via webhooks
- City updates. 150K cities = too much churn for webhooks. Use
cities/{id}withIf-Modified-Sinceinstead. - API key events. These are account-level, not data-level. Different webhook type (planned).
- IP geolocation events. No "fired when an IP changes country" semantic exists. Just re-call the endpoint.
Webhooks are a paid-tier feature on ApogeoAPI (Basic and above). Free tier customers should poll endpoints with conservative TTLs instead. Get started at apogeoapi.com — 14-day full trial includes webhooks.
Try ApogeoAPI free
1,000 requests/month forever. 14-day full-access trial. No credit card.
Get your free API key