Postal codes look nothing alike across countries: five digits in Spain, SW1A 1AA in the UK, K1A 0B1 in Canada. The /v1/places/postal-format endpoint gives you the format, the official regular expression and a sample value per country, so your form can validate the field in the browser and show a placeholder that makes sense.
GET https://api.countrydataapi.com/v1/places/postal-format
| Parameter | Type | Required | Description |
|---|---|---|---|
apikey |
string | Yes | Your API authentication key |
country |
string | No | Internal id, ISO-2, ISO-3 or name. Omit to get every country |
lang |
string | No | Language of the country names. Defaults to en |
curl "https://api.countrydataapi.com/v1/places/postal-format?apikey=your-api-key&country=ES"
const response = await fetch(
'https://api.countrydataapi.com/v1/places/postal-format?apikey=your-api-key'
);
const { data } = await response.json();
// Index by ISO-2 for instant lookups in the form
const formats = Object.fromEntries(
data.map(({ country, postal }) => [country.iso2, postal])
);
localStorage.setItem('postal_formats', JSON.stringify(formats));
const { data } = await api.places.postalFormat({ country: 'ES' });
data[0].postal.regex; // "^\\d{5}$"
{
"success": true,
"data": [
{
"country": {
"id": "66c7a6c9e4bda21f4ab10ef2",
"name": "Spain",
"iso2": "ES",
"iso3": "ESP",
"phone_code": "+34",
"flag": "🇪🇸"
},
"postal": {
"format": "#####",
"regex": "^\\d{5}$",
"example": "12345"
}
}
],
"count": 1,
"tokens_used": 1,
"remaining_tokens": 4869
}
format template| Symbol | Meaning |
|---|---|
# |
A digit |
@ |
A letter |
| anything else | A literal character (space, dash, country prefix...) |
So @@# #@@ describes a UK postcode and produces the example AB1 2CD.
example is generated from format and then checked against regex. If the two disagree, example is null rather than a made-up value you cannot trust. Countries with no postal system return null in all three fields.
function validatePostcode(value, iso2) {
const postal = formats[iso2];
if (!postal?.regex) return true; // no pattern on record: accept anything
return new RegExp(postal.regex).test(value.trim());
}
// Also useful as a placeholder
input.placeholder = formats[iso2]?.example ?? '';
Validating client-side is a UX improvement, not a guarantee. A well-formed postcode is not necessarily a real one — confirm it with /v1/places/validate before shipping anything to it.
1 token per request, whether you ask for one country or all of them.
This data barely changes. Fetch the full list once, cache it, and you will not need this endpoint again for months. You are free to store it for as long as you want.