Check a postal code
Enter 28013 with Spain and it is confirmed as a well-formed Spanish postal code; the same check knows a US ZIP has five digits and a Canadian code alternates letters and numbers. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
A postal code that looks fine to the eye can still break a shipping label, a tax calculation, or a CRM import.
The problem with 'looks right'
Postal systems are not standardized. A US ZIP is five digits, sometimes nine with a hyphen. A Canadian code alternates letters and numbers.
A UK postcode has a length that varies by region and a format that trips up even native scripts.
What the check really looks at
The task validates the string against the structural pattern used by that country's postal authority: digit counts, letter positions, separators, and known reserved ranges where applicable. It confirms the code is well-formed for that country; it does not confirm the code corresponds to a real, currently assigned delivery area, since postal boundaries change and that data is not something we fabricate or guess at.
A quick history most people never think about
Postal codes are younger than most assume. Germany introduced a numeric system in the 1940s, the United States rolled out ZIP codes in 1963, and the UK's alphanumeric postcodes were phased in gradually through the 1970s and 80s. Because each country built its system independently, to solve local sorting problems with local infrastructure, there is no universal pattern.
That's precisely why format validation needs a maintained, per-country rule set rather than a single regular expression someone wrote once and forgot about.
Where it fits in your pipeline
Call it inline during checkout or signup for immediate feedback, or run it in bulk against an existing customer or shipping database to flag records worth a second look. Nothing here requires you to bolt geocoding or address-completion logic onto a simple validation step.
What it's not
This is a format checker, not a full address verification suite. It won't tell you a street exists or that a courier delivers there. Used for what it is, it's a cheap, fast, precise filter that removes a large share of obviously broken entries before they cost you a failed delivery or a bounced invoice.
What you can do with it
Checkout form validation
Validate the postal code field in real time as a customer fills out shipping details, before the order is placed and the label is printed.
Customer database cleanup
Run a bulk pass over an aging CRM export to flag postal codes that no longer match the expected format for their listed country.
Multi-country signup forms
Apply the correct country-specific pattern automatically instead of maintaining your own table of regular expressions for 200+ postal systems.
FAQ
Does it support countries outside the US?
Yes, it covers postal formats for more than 200 countries and territories, each checked against its own pattern rather than a generic rule.
Is there a free tier or trial?
The tool above runs free in your browser. No subscription, no tokens, and a failed task is never charged.
What happens if a task fails?
The system retries automatically up to three times. If it still fails, you get a clear error and you are not charged for it.
Can I validate postal codes in bulk?
Yes, since every task runs asynchronously, you can queue large batches without blocking your application while results come back.
Does a valid postal code mean the address exists?
No. It means the code has the right shape for its country, with the right number of digits, letters in the right places and correct separators. It does not confirm a real, currently assigned delivery area, because postal boundaries change.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/verify/postal-code \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"postal_code":"28001","country":"ES"}'const res = await fetch("https://api.kit.forhosting.com/verify/postal-code", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"postal_code": "28001",
"country": "ES"
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/verify/postal-code",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"postal_code": "28001",
"country": "ES"
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/verify/postal-code", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"postal_code":"28001","country":"ES"}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"postal_code":"28001","country":"ES"}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/verify/postal-code", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"postal_code": "28001",
"country": "ES"
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "verify.postal_code",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
This zip code validation API checks the format of a postal code against the pattern rules of its country, catching typos and malformed entries the moment they're typed, not after the parcel bounces back.
The problem with 'looks right'
When a checkout form or a signup page accepts anything typed into a text box, a meaningful share of addresses end up unroutable, and someone downstream has to fix it by hand. This endpoint exists to catch that before it becomes a support ticket.
What the endpoint actually checks
You send a postal code and a country identifier to POST /verify/postal-code.
Where it fits in your pipeline
Because every task is asynchronous, you queue the request, keep your form responsive, and receive the result through a signed webhook or a signed link valid for 24 hours.
Integration use cases
Logistics pre-checks
Filter a batch of orders before handing them to a carrier API, reducing the rate of failed label generation caused by malformed input.
Technical questions
What does this zip code validation API actually verify?
It checks that a postal code matches the structural format expected for the given country: correct digit or letter count, separators, and known patterns. It does not confirm the code is currently in active use.
How much does each request cost?
$0.002 per request, billed only on tasks that complete successfully.
How do I get the result back?
Every call to POST /verify/postal-code returns a task_id immediately; the result is delivered via a signed webhook, or you can fetch it from a signed link valid for 24 hours.
Does it verify deliverability, not just format?
No, it's strictly a format check. Confirming an address is deliverable requires courier or postal-authority data this endpoint doesn't claim to have.