Batch IP Lookup API: First Request
You need to look up geolocation and network details for many IPs at once, without hand-rolling loops or burning time on one-by-one requests. By the end of this guide, you will send your first authenticated batch request to the ipXapi Batch IP Lookup API, parse the results you need, and know the practical limits and behaviors to ship an integration safely.
What you will build
You will make a single HTTP POST to the Batch IP endpoint with a small list of IPs, receive a structured array of results, and extract fields such as countryCode, region, city, and security flags. You will do this using a copy-pasteable cURL and a short Python example that you can adapt into your service or job runner.
This walkthrough focuses only on what’s required for a first working call. Once you have it returning data, you can expand to larger inputs (up to the documented limit) and add application-level reliability features like retries or caching.
Before you start: prerequisites and auth
To call the Batch IP endpoint, you need:
- An ipXapi account and API key. You can create one in minutes via Register.
- Bearer authentication. Send your key in the Authorization header as: Authorization: Bearer YOUR_API_KEY.
- JSON request body with a list of IP strings.
Key constraints to be aware of:
- Endpoint: POST /api/batch-ip.
- Body format: JSON array of IP addresses.
- Maximum IPs per request: 1024.
- Credits: n + 1 (one extra service credit on top of the number of IPs in your batch).
If you want to explore endpoints interactively or wire this into internal tooling, ipXapi also provides an MCP-compatible surface at MCP.
Make your first batch request
The snippet below is the documented cURL example for a two-IP batch. Replace ONLY the API key value with your own before running it. The IPs should remain exactly as shown for this first test.
cURL
curl -X POST "https://ipxapi.com/api/batch-ip" -H "Authorization: Bearer YOUR_KEY" -H "Content-Type: application/json" -d '["66.165.2.7","190.191.2.241"]'
Notes that save time:
- Content-Type is application/json. The request body must be a valid JSON array of quoted IP strings.
- Use HTTPS. Some environments silently rewrite or block non-HTTPS calls; start with HTTPS to avoid confusing TLS or redirect issues.
- Do not add extraneous fields. The Batch IP endpoint expects an array, not an object with keys.
- Plan for n + 1 credits per request. If you batch 100 IPs, that consumes 101 credits.
Understand the response
Below is the official docs example for a response row. Your actual results will reflect the IPs you submit, but this sample shows the structure and the field names your code should read. Keep in mind that the “query” field in the official example below is a different IP than the two used in the cURL body; that’s expected for this documentation fixture.
Official JSON sample
{
"results": [
{
"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",
"security": {
"is_proxy": false,
"is_vpn": false,
"is_cloud_provider": true
}
}
]
}
What to read from each result entry:
- status: Check for "success" before trusting other fields.
- country, countryCode, region, regionName, city, zip: Basic geo attributes. Timezone is an IANA identifier (e.g., America/Los_Angeles).
- lat, lon: Coordinates in decimal degrees.
- isp, org, as: Network ownership/route context. Helpful for analytics or access policies.
- query: The IP that this particular result describes.
- security.is_proxy / is_vpn / is_cloud_provider: Boolean flags you can use to inform risk checks.
Parsing tip: Because this is a batch endpoint, the response aggregates results under results. Treat each element as independent. Use the "query" field to correlate results to input IPs if you need to rebuild ordering or deduplicate downstream.
Minimal Python example
The script below posts the same two IPs as the cURL example, checks the status for each result, and prints a short summary. Copy, set YOUR_API_KEY, and run.
Python
import json
import sys
import urllib.request
API_URL = "https://ipxapi.com/api/batch-ip"
API_KEY = "YOUR_API_KEY" # Replace with your ipXapi key
IPS = ["66.165.2.7", "190.191.2.241"] # Up to 1024 IPs per request
def batch_lookup(ips):
data = json.dumps(ips).encode("utf-8")
req = urllib.request.Request(
API_URL,
data=data,
method="POST",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
},
)
try:
with urllib.request.urlopen(req, timeout=30) as resp:
payload = resp.read().decode("utf-8")
return json.loads(payload)
except urllib.error.HTTPError as e:
sys.stderr.write(f"HTTP error: {e.code} {e.reason}\n")
if e.fp:
sys.stderr.write(e.fp.read().decode("utf-8") + "\n")
raise
except urllib.error.URLError as e:
sys.stderr.write(f"Request failed: {e.reason}\n")
raise
if __name__ == "__main__":
result = batch_lookup(IPS)
results = result.get("results", [])
for entry in results:
status = entry.get("status")
ip = entry.get("query")
if status != "success":
print(f"{ip}: lookup not successful (status={status})")
continue
cc = entry.get("countryCode")
region = entry.get("region")
city = entry.get("city")
tz = entry.get("timezone")
isp = entry.get("isp")
sec = entry.get("security", {}) or {}
is_proxy = sec.get("is_proxy")
is_vpn = sec.get("is_vpn")
is_cloud = sec.get("is_cloud_provider")
print(f"{ip} -> {cc} {region} {city} | tz={tz} | isp={isp} "
f"| proxy={is_proxy} vpn={is_vpn} cloud={is_cloud}")
Implementation notes:
- Timeouts: Use a client timeout (30s above) so misconfigured networks do not stall your worker indefinitely.
- Error handling: Check the per-entry status, not just HTTP status. Handle unexpected structures defensively by defaulting missing keys.
- Mapping results: Rely on the query field to associate each result with its input IP.
Practical behaviors and integration tips
These details prevent common pitfalls and keep your integration workable under load.
- Batch size: The maximum is 1024 IPs per POST. If you have more, split into multiple requests. Consider right-sizing batches to balance throughput and failure isolation.
- Credits: The call consumes n + 1 credits for n IPs. Plan your batching strategy accordingly to meet your monthly credit budget and latency needs.
- Input validation: Ensure each item in the array is a properly formatted IPv4 or IPv6 string (if applicable in your usage). Reject or log invalid inputs before sending.
- Deduplication: If your input list may contain repeats, deduplicate beforehand to reduce credit usage and processing time. If you need counts by IP, deduplicate for the API call and expand back in your app’s logic.
- Correlation: Use the query field to correlate outputs. Do not assume the response order always mirrors the request order in all environments; write code that uses query as the key.
- Serialization: The body must be a strict JSON array. Avoid trailing commas or comments. Validate your payload before sending.
- Timezone and coordinates: timezone uses IANA TZ identifiers (e.g., America/Los_Angeles). lat and lon are decimal degrees and can be used directly with mapping libraries.
- Security flags: Treat security flags as signals you can combine with your own rules. For example, you might step up auth when is_vpn is true.
- Caching: Cache successful lookups in your app keyed by IP. Refresh on a schedule that fits your data’s freshness requirements. Caching reduces credits and latency for repeated lookups.
- Operational hygiene: Log request sizes, credits consumed, and any non-success statuses in the results array to help troubleshoot patterns over time.
Testing and debugging your first request
Start with the official example body exactly as shown, then gradually introduce your own IPs. If you encounter errors:
- Authorization header: Verify it is Authorization: Bearer YOUR_API_KEY with no extra spaces or missing “Bearer”.
- Content-Type: Must be application/json. Incorrect content types often cause server-side body parsing errors.
- Body shape: Ensure a JSON array of strings, not an object. Try echoing your request payload to confirm it serializes correctly.
- Visibility: If running behind a corporate proxy, ensure that HTTPS egress to ipxapi.com is allowed.
Once the basic round trip works, expand the IP list and observe performance and logs. Build guardrails in your job runner to retry transient network errors while stopping on persistent serialization or authentication errors.
Where to go next
Review the reference for any field clarifications and additional examples in the Documentation. If you manage internal tools, consider integrating the API via MCP so your team can explore endpoints consistently in one place.
FAQ
How many IPs can I send in one batch?
Up to 1024 IPs per POST to /api/batch-ip. If you have more, split the work into multiple requests.
How are credits calculated for batch requests?
Credits are n + 1, where n is the number of IPs in your batch payload.
Which authentication method should I use?
Use a Bearer token in the Authorization header: Authorization: Bearer YOUR_API_KEY.
How do I match results to my input IPs?
Use the query field in each result entry. Do not rely solely on array positions; map by query to be safe.
What fields should I check first after a request?
For each result, read status before consuming other fields. Then extract the geo fields you need (e.g., countryCode, region, city) and any security flags relevant to your use case.
Ship it
You now have a working request and a minimal client that reads the fields you’ll actually use. Create your key and run your first batch today via Register, then wire the endpoint into your tooling or internal service. If you prefer a standardized interface for exploration and integration, check out MCP as a next step.
