IP Geolocation IP API: First Request with curl and JSON
You need to fetch reliable geolocation data for a specific IP address and quickly integrate it into your application. By the end of this guide, you will make a working, authenticated curl request to ipXapi’s IP Geolocation endpoint, understand the returned JSON, and replicate the same call in a short Python script ready to paste into your project.
What you will build and what you need
This walkthrough focuses on one task: performing a geolocation lookup via the ipXapi IP Geolocation endpoint using Bearer authentication. You will:
- Send your first authenticated request with curl to the /api/ip path.
- Parse the official product-fixture JSON for a known IP.
- Translate the same call into a minimal Python script.
- Learn practical handling tips (time zones, caching, and changes in live flags).
Prerequisites are minimal: a command line with curl installed and a programming environment (Python) if you want to run the sample code. To obtain an API key and manage access, use the Register link and see the Documentation. If you prefer a control-plane experience for exploring capabilities, you can also visit the MCP.
Endpoint and authentication model
The IP Geolocation lookup is performed against the following path:
- HTTP path: /api/ip
Authentication is handled via an Authorization header using the Bearer scheme. This guide shows a request that specifies the target IP with a query parameter and includes two headers: Accept and Authorization.
Make your first geolocation request with curl
The example below uses a documented fixture IP and returns the official product-fixture JSON. Replace YOUR_KEY with your actual Bearer token when you run it. Do not treat this fixture response as your own IP, and be aware that live flags can change.
Code: curl request
curl "https://ipxapi.com/api/ip?ip=148.105.12.120" -H "Accept: application/json" -H "Authorization: Bearer YOUR_KEY"
Understand the JSON response
The following is the official product-fixture JSON for the same IP address. Use it to validate parsing in your application. When you make live requests, values can differ depending on the target IP and current data.
Response: official product-fixture JSON
{"status":"success","country":"United States","countryCode":"US","region":"US-CA","regionName":"California","city":"Mountain View","zip":"94043","lat":37.40599,"lon":-122.0786,"timezone":"America/Los_Angeles","isp":"MailChimp","org":"MailChimp","as":"AS14782 MailChimp","query":"148.105.12.120","inEU":false,"continentCode":"NA","security":{"is_proxy":false,"is_vpn":false,"is_cloud_provider":true}}
What you will commonly use
- status: Overall status of the lookup.
- query: The IP address that was looked up.
- country, countryCode, region, regionName, city, zip: Core geolocation fields for country/subdivision/city-level attribution.
- lat, lon: Coordinates that you can map or use for geo-based rules.
- timezone: IANA time zone identifier (e.g., America/Los_Angeles). Useful for displaying local times and scheduling logic.
- isp, org, as: Network and ASN details that can drive access control or analytics.
- inEU, continentCode: Regional or regulatory classification helpers.
- security: Object with is_proxy, is_vpn, is_cloud_provider flags for security and risk-based decisions.
Units and formats:
- lat and lon are decimal degrees.
- timezone is an IANA zone string suitable for time libraries.
- countryCode, region, continentCode are short codes; country and regionName are full names.
Repeat the same call in Python
This short Python example mirrors the curl request against /api/ip with the same fixture IP. It sets the Bearer token in the Authorization header and reads a subset of fields you will typically need.
Code: Python
import json
import sys
import urllib.request
url = "https://ipxapi.com/api/ip?ip=148.105.12.120"
req = urllib.request.Request(
url,
headers={
"Accept": "application/json",
"Authorization": "Bearer YOUR_KEY",
},
)
try:
with urllib.request.urlopen(req, timeout=15) as resp:
data = json.loads(resp.read().decode("utf-8"))
except Exception as e:
print("Request failed:", e, file=sys.stderr)
sys.exit(1)
# Access a few key fields for application logic
status = data.get("status")
ip = data.get("query")
country = data.get("country")
region = data.get("regionName")
city = data.get("city")
lat = data.get("lat")
lon = data.get("lon")
tz = data.get("timezone")
isp = data.get("isp")
security = data.get("security") or {}
is_proxy = security.get("is_proxy")
is_vpn = security.get("is_vpn")
is_cloud = security.get("is_cloud_provider")
print("status:", status)
print("ip:", ip)
print("country:", country)
print("region:", region)
print("city:", city)
print("lat,lon:", lat, lon)
print("timezone:", tz)
print("isp:", isp)
print("security flags:", {"proxy": is_proxy, "vpn": is_vpn, "cloud": is_cloud})
Practical integration details that save time
Time zones and timestamps:
- The timezone field returns an IANA identifier such as America/Los_Angeles. Use this directly with time libraries that accept IANA zones for accurate conversions and scheduling.
- When rendering time-sensitive UI for users from different locations, store timestamps in UTC in your data model and convert to timezone on display.
Caching and update patterns:
- IP geolocation often remains stable, but network and security attributes (e.g., is_proxy, is_vpn, is_cloud_provider) can change. If your product relies on these flags, consider a shorter cache for security fields than for country/region/city fields.
- Cache the full JSON by IP to reduce latency and request volume in hot paths. Invalidate or refresh the cache periodically based on your risk tolerance.
- Store both raw JSON and normalized fields in your database so you can reprocess records if field mappings evolve.
Handling differences between fixture and live data:
- The JSON shown above is a product fixture for the documented IP. In production, the values will reflect the live data for the IP you query.
- Do not hardcode assumptions from the fixture; handle missing, null, or changing values defensively.
Error handling and robustness:
- Check status in the JSON before trusting downstream fields. If status indicates a failure, log the response body for inspection.
- Guard map lookups for nested objects like security to avoid KeyError exceptions.
- Use timeouts in your HTTP client to prevent requests from hanging.
IP address sourcing and validation:
- If you use client IPs from HTTP headers, validate your reverse proxy and trust chain to avoid spoofing. Prefer server-derived connection IP when possible.
- Normalize IPv6 and IPv4-mapped IPv6 forms in your own data model; confirm the format you pass to the API matches what you intend to look up.
Field-by-field notes for application logic
Country and region logic:
- Use countryCode for compact branching in code paths and reporting. Map it to country for display text.
- region and regionName provide subnational resolution; region is a short code; regionName is suitable for UI.
Location precision and UX:
- lat and lon are adequate for map centering and approximations. Do not infer street-level precision.
- Combine city and zip for display, but always guard for missing zip where unavailable.
Network and ASN implications:
- isp, org, and as can identify hosting providers or enterprise networks. Use these for analytics, B2B routing, or fraud rules.
- For security hardening, prefer security.is_cloud_provider as a stronger signal of cloud-hosted origins than ASN name alone.
Regulatory flags:
- inEU and continentCode support compliance experiences (e.g., consent flows). When you use them, log the resolved values for auditability.
Security flags in practice:
- Use is_proxy and is_vpn for risk scoring rather than binary blocking where possible. Many users rely on privacy tools; apply adaptive friction instead of blanket denial if your use case allows.
- is_cloud_provider is helpful for distinguishing data center traffic from residential ranges, especially for bot detection or rate limiting.
Step-by-step: moving from test to production
1) Get an API key
Sign up to obtain your credentials via Register. Keep the token secret and rotate it on a schedule that matches your security policy.
2) Verify connectivity and headers
Start with the exact curl shown in this guide. Replace YOUR_KEY with your token, confirm a 200 response, and validate that status is success in the JSON. If you’re behind a corporate proxy, set curl’s proxy variables as required by your environment.
3) Integrate the endpoint call in your service
Use the Python snippet here to wire a minimal integration, then move the token to a secure store (environment variable or your secrets manager). Apply a sane timeout and add logging to record the input IP, HTTP status, and a response hash for observability.
4) Normalize and store the fields you need
Decide which fields to persist (e.g., countryCode, regionName, city, lat, lon, timezone, isp, security flags). Store both raw JSON and a compact derivative model so you can refactor easily if new fields arrive in the response.
5) Add caching and refresh
Introduce a cache keyed by IP. For infrequently changing attributes (country/city/coordinates), a longer TTL is reasonable. For security flags, prefer a shorter refresh to capture evolving risk signals. Document your refresh strategy in your runbook.
6) Build guards and fallbacks
Handle temporary failures by retrying with backoff, and fall back to last-known-good data in your cache. If a field is missing, ensure your app degrades gracefully rather than failing a transaction.
Testing strategies for geolocation logic
Deterministic fixtures:
- Use the documented fixture IP 148.105.12.120 during test runs to verify parsing, code paths, and template rendering against the known JSON above.
Behavioral tests:
- Write tests that branch on countryCode, regionName, and timezone and ensure expected variations in UI or access policies.
- Simulate risk-based flows by toggling security flags in local test doubles; keep live tests separate since real-time flags vary.
Operational tests:
- Exercise timeouts and error handling by injecting failures. Verify your logs record the request URL, response status, and a minimal redacted payload for debugging.
Troubleshooting: common issues and fixes
- 401 or 403 errors: Ensure the Authorization header is present and starts with Bearer followed by your token. Confirm that your token has not expired or been revoked.
- Unexpected or missing fields: Always access nested objects defensively (e.g., data.get("security") or {}). Log the raw JSON during early integration to spot mismatches quickly.
- Incorrect client IP: If you are behind a load balancer, verify where you source the IP in your app, and ensure your proxy chain is trustworthy before using header-derived addresses.
- Time zone confusion: Use the timezone field directly with IANA-aware libraries; avoid manual offset math that can break during DST transitions.
- Caching mistakes: Separate TTL strategy for security flags from location attributes. Avoid caching permanent errors; cache only valid responses.
FAQ
Q: Which endpoint should I call for an IP geolocation lookup?
A: Call the IP Geolocation path /api/ip and pass the IP as a query parameter, as shown in the curl example.
Q: How do I authenticate?
A: Use an Authorization header with the Bearer scheme (Authorization: Bearer YOUR_KEY). Obtain your token via the Register link.
Q: Are the JSON fields stable across IPs?
A: The schema shown here reflects the documented fixture. Live values vary by IP, and some fields can be absent. Access fields defensively and log raw responses when integrating.
Q: How should I handle time zones?
A: Use the timezone field’s IANA identifier in your time library to convert and display local times correctly. Keep your source timestamps in UTC.
Q: Should I cache results?
A: Yes. Cache geolocation fields with a longer TTL and consider a shorter refresh for security flags (is_proxy, is_vpn, is_cloud_provider) since they can change more frequently.
Ready to integrate? Create your key via Register, review the Documentation for additional details, and explore the MCP to manage and iterate on your geolocation workflows.
