Authentication
Every request to the IPWho API must be authenticated with your API key. You can get a key — free, 2,000 lookups/day, no credit card — from the free plan page. This page covers the three ways to send the key, which to prefer, and how authentication errors surface.
Choose how to send your key
Section titled “Choose how to send your key”The API accepts your key three ways. All three return the same response; they differ only in how exposed the key is.
1. Authorization header (recommended)
Section titled “1. Authorization header (recommended)”Send the key as a Bearer token. This keeps it out of request URLs, browser history, proxy logs, and analytics — the safest option for server-side code.
curl -sS -H "Authorization: Bearer sk.xxx" \ "https://api.ipwho.org/ip/8.8.8.8"2. X-API-Key header
Section titled “2. X-API-Key header”A plain custom header, equivalent in security to the Bearer form. Use whichever fits your HTTP client’s conventions.
curl -sS -H "X-API-Key: sk.xxx" \ "https://api.ipwho.org/ip/8.8.8.8"3. Query parameter (quickest to try)
Section titled “3. Query parameter (quickest to try)”Append apiKey to the URL. This is the fastest way to test a call, but the key
becomes part of the full URL — which is commonly written to server logs, browser
history, and referrer headers. Prefer a header for anything beyond a quick test.
curl -sS "https://api.ipwho.org/ip/8.8.8.8?apiKey=sk.xxx"Keep your key out of source code
Section titled “Keep your key out of source code”Load the key from an environment variable rather than hardcoding it, and never commit it to version control:
import os, urllib.request, json
API_KEY=os.env...Y"] # set it in your environment, not in code
req = urllib.request.Request( "https://api.ipwho.org/ip/8.8.8.8", headers={"Authorization": f"Bearer {API_KEY}"},)with urllib.request.urlopen(req, timeout=10) as resp: data = json.loads(resp.read())Authentication errors
Section titled “Authentication errors”When a key is missing or invalid, the API responds with HTTP 401 and a JSON
body describing the problem:
{ "error": "missing_api_key" }{ "error": "invalid_api_key" }Handle these by checking the HTTP status before parsing the response, and surface
a clear message to the caller rather than retrying — a 401 will not succeed on
retry with the same key.
Related
Section titled “Related”- Overview — make your first request
- Rate limits — quotas and limits
- Client SDKs — typed clients that handle auth for you