Working code using requests, Flask, and Django. Get a
free API key and start making live ZIP code lookups in minutes.
The ZipCodesToGo ZIP Code API is a REST API that returns JSON. In Python,
the simplest integration uses the requests library. Pass your API key in the
X-Api-Key header and parse the data key from the response.
import requests API_KEY = 'zcg_your_key_here' API_BASE = 'https://api.zipcodestogo.com/v1' response = requests.get( f'{API_BASE}/zip/90210', headers={'X-Api-Key': API_KEY} ) response.raise_for_status() # raises HTTPError on 4xx/5xx data = response.json()['data'] print(data['city']) # Beverly Hills print(data['state']) # CA print(data['lat']) # 34.0901 print(data['timezone']) # America/Los_Angeles
import os import re import requests from requests.exceptions import HTTPError, RequestException API_KEY = os.environ.get('ZIP_API_KEY') # store in env API_BASE = 'https://api.zipcodestogo.com/v1' def lookup_zip(zip_code: str) -> dict: """Return location data for a US ZIP code.""" if not re.fullmatch(r'\d{5}', zip_code): raise ValueError(f'Invalid ZIP code: {zip_code}') try: res = requests.get( f'{API_BASE}/zip/{zip_code}', headers={'X-Api-Key': API_KEY}, timeout=5 ) res.raise_for_status() return res.json()['data'] except HTTPError as e: status = e.response.status_code if status == 404: raise ValueError(f'ZIP {zip_code} not found') if status == 401: raise PermissionError('Invalid API key') if status == 429: raise RuntimeError('Rate limit reached') raise except RequestException as e: raise RuntimeError(f'Network error: {e}') # Usage if __name__ == '__main__': location = lookup_zip('10001') print(f'{location["city"]}, {location["state"]}') # New York, NY
from flask import Flask, jsonify, request, abort from zip_client import lookup_zip # from the example above app = Flask(__name__) @app.route('/location') def get_location(): zip_code = request.args.get('zip', '').strip() if not zip_code: abort(400, description='zip parameter required') try: data = lookup_zip(zip_code) return jsonify(data) except ValueError as e: abort(404, description=str(e)) except RuntimeError as e: abort(503, description=str(e)) # GET /location?zip=90210 # → {"city":"Beverly Hills","state":"CA","county":"Los Angeles",...}
import pandas as pd from zip_client import lookup_zip import time df = pd.read_csv('customers.csv') # must have a 'zip' column def enrich(zip_code): try: d = lookup_zip(str(zip_code).zfill(5)) return pd.Series({'city': d['city'], 'state': d['state']}) except Exception: return pd.Series({'city': None, 'state': None}) # Respect daily rate limits — add a small sleep between rows results = [] for zip_code in df['zip']: results.append(enrich(zip_code)) time.sleep(0.05) # ~20 req/s, well within limits df[['city', 'state']] = pd.DataFrame(results) df.to_csv('customers_enriched.csv', index=False) print('Done.')
| Status | Meaning | Python handling |
|---|---|---|
200 | Success | Parse response.json()['data'] |
404 | ZIP not found | Catch HTTPError, check status_code == 404 |
401 | Bad API key | Check your env variable value |
429 | Rate limit | Add time.sleep() or upgrade plan |
5xx | Server error | Retry with backoff: tenacity library |