Monitor your key's usage before you hit a limit
Watching your quota headers as you go tells you when a limit is approaching, well before a request actually gets rejected.
A customer export with a postal code column but no coordinates is a common starting point for anything involving shipping zones, regional reporting, or store assignment. Resolving the whole column at once is faster than writing a loop.
POST an array of code and country objects to /v1/postcode. Each item resolves independently and comes back in the same order.
POST /v1/postcode
Content-Type: application/json
[{"code": "10115", "country": "DE"}, {"code": "75001", "country": "FR"}]{
"status": "ok",
"results": [
{"postcode": "10115", "country_code": "DE", "results": [{"lat": 52.5300, "lon": 13.3800, "components": {"city": "Berlin", "region": "Berlin"}}]},
{"postcode": "75001", "country_code": "FR", "results": [{"lat": 48.8630, "lon": 2.3360, "components": {"city": "Paris", "region": "Ile-de-France"}}]}
]
}Keep the original row index or customer ID alongside each code and country pair before sending the request, and match results back onto customer records by that same position, the same approach that works for bulk forward or reverse geocoding.
A customer list of any real size tends to have far fewer distinct postal codes than it has rows, since many customers share the same code in any given city or neighborhood. Build a unique list of code and country pairs first, resolve that smaller list in one batch, and then map the results back onto every customer row that shares each code, rather than sending one array entry per customer and paying for the same code and country pair over and over.
An empty results array for a particular item usually means the code and country pair does not exist, which is common in an old export with typos or an outdated postal code. Flag those rows for manual review rather than silently dropping them from your report.
A code stored as "SW1A1AA" without a space and one stored as "SW1A 1AA" with one may or may not resolve the same way depending on how consistently your own export formats codes, so normalizing spacing and case in your export before building the batch array reduces the number of rows that fail to resolve purely on formatting rather than on the code being genuinely wrong.
A batch is billed one request per item, so a 2,000 row customer list costs 2,000 requests, whether sent as one bulk call or as 2,000 separate ones. Sending it as one call is still worth doing for the reduced overhead and the single set of quota headers to check, even though the request count against your allowance is identical either way. Deduplicating first, as above, is what actually reduces the request count, not the choice between bulk and individual calls.
For a list large enough to run past the free 2,500 requests a day, check X-Quota-Free-Remaining before you commit to running the whole thing in one sitting, or split it across a couple of days if you are not planning to move onto prepaid credit for a one-off job.
Resolving a whole customer list's postal codes in a single call turns what used to be a slow background job into one straightforward request. The postal code lookup docs cover the full field list.