Batch IP API
You need to resolve IP geolocation, detect proxies and VPNs, read ASN/ISP/organization, and score IP reputation signals at scale. By the end of this post you will send a single request to look up many IPs at once, parse the response for location and security indicators, and ship a production-ready integration using the Batch IP endpoint.
What the Batch IP endpoint returns and why it’s useful
The Batch IP endpoint aggregates essential network intelligence for each queried IP address in one response. You can extract:
- Geolocation: country, region, city, ZIP, latitude, longitude, and timezone for routing and localization.
- Network: ASN string (as), ISP, and organization for traffic analysis and policy decisions.
- Security signals: proxy, VPN, and cloud-provider flags for fraud and abuse prevention.
Instead of firing one request per IP, you submit a list and receive results together. This reduces overhead, keeps your pipelines simpler, and helps maintain consistent behavior under load.
Endpoint, method, authentication, and quotas
The Batch IP lookup runs on a single HTTP POST:
- Path: /api/batch-ip
- Method: POST
- Body: a JSON array of IP strings
- Max IPs per call: 1024
- Credits consumed: n+1 (one per IP plus one overhead credit)
- Authorization: Bearer YOUR_KEY (send via Authorization header)
Plans: the Basic plan is $29.99/mo. A trial is available for 7 days or 50 requests. For plan specifics and current limits, check the Documentation.
Request format and bodies that work for local testing
Use the documented fixture to validate your integration and CI checks. The body is a JSON array containing two IPs. This is accepted by the API and is small enough for smoke tests:
- Fixture body: ["66.165.2.7","190.191.2.241"]
Send Content-Type: application/json and include your API key in the Authorization header. Do not modify the fixture for first-run tests.
Official cURL you can copy and run
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"]'
Official JSON sample and how to read the fields
{
"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
}
}
]
}
Field usage notes:
- results: an array containing one object per queried IP address (your integration should iterate this array).
- status: check for "success" before consuming data.
- country, countryCode, region, regionName, city, zip: textual geolocation attributes for routing and UI labeling.
- lat, lon: numeric coordinates; treat as decimal degrees.
- timezone: IANA timezone identifier for consistent timestamp rendering and scheduling.
- isp, org: network ownership context.
- as: ASN string, useful for policy rules or analytics.
- query: the IP the row refers to (always read this to correlate results to inputs).
- security.is_proxy, security.is_vpn, security.is_cloud_provider: booleans for common risk vectors and infrastructure classification.
End-to-end JavaScript example (Node.js) for /api/batch-ip
This example sends the documented fixture, checks the status field, and extracts geolocation, ASN, and security flags to a normalized record you can store or stream.
import https from "https";
const API_URL = "https://ipxapi.com/api/batch-ip";
const API_KEY = "YOUR_KEY"; // Authorization: Bearer YOUR_KEY
const BODY = ["66.165.2.7","190.191.2.241"];
function requestBatch(body) {
const payload = Buffer.from(JSON.stringify(body));
return new Promise((resolve, reject) => {
const req = https.request(API_URL, {
method: "POST",
headers: {
"Authorization": "Bearer " + API_KEY,
"Content-Type": "application/json",
"Content-Length": String(payload.length)
},
timeout: 15000
}, (res) => {
let data = "";
res.setEncoding("utf8");
res.on("data", (chunk) => { data += chunk; });
res.on("end", () => {
if (res.statusCode >= 200 && res.statusCode < 300) {
try {
resolve(JSON.parse(data));
} catch (e) {
reject(new Error("Invalid JSON in response"));
}
} else {
reject(new Error("HTTP " + res.statusCode + " - " + data));
}
});
});
req.on("error", reject);
req.on("timeout", () => {
req.destroy(new Error("Request timed out"));
});
req.write(payload);
req.end();
});
}
function normalize(row) {
if (!row || row.status !== "success") {
return null;
}
const security = row.security || {};
return {
ip: row.query,
country: row.country,
countryCode: row.countryCode,
region: row.region,
regionName: row.regionName,
city: row.city,
zip: row.zip,
latitude: row.lat,
longitude: row.lon,
timezone: row.timezone,
isp: row.isp,
org: row.org,
asn: row.as,
is_proxy: security.is_proxy === true,
is_vpn: security.is_vpn === true,
is_cloud_provider: security.is_cloud_provider === true
};
}
(async () => {
try {
// 1) Send the documented fixture
const json = await requestBatch(BODY);
// 2) Parse and map each result
const results = Array.isArray(json && json.results) ? json.results : [];
// 3) Maintain original order by trusting the array order from the API
const mapped = results.map(normalize).filter((x) => x !== null);
// 4) Use or store the mapped data
// Example: print summary lines for dashboards or logs
for (const r of mapped) {
console.log(
[
"ip=" + r.ip,
"country=" + r.countryCode,
"region=" + r.region,
"city=" + r.city,
"asn=" + r.asn,
"isp=" + r.isp,
"vpn=" + String(r.is_vpn),
"proxy=" + String(r.is_proxy),
"cloud=" + String(r.is_cloud_provider),
"tz=" + r.timezone
].join(" ")
);
}
} catch (err) {
console.error("Batch-IP error:", err.message);
process.exitCode = 1;
}
})();
Production considerations that save time
Batch sizing and credits
Each call consumes n+1 credits, where n is the number of IPs in your submitted array. If you can group related IPs into larger batches (up to 1024), you reduce the fixed overhead per call. Fit batching to your pipeline checkpoints and backfills rather than firing per-event calls.
Idempotence and correlation
Always correlate results by reading query from each row when merging with upstream event logs. This makes your pipeline robust to reorderings or deduplication passes if you reshuffle the input array.
Caching window
IP attributes such as ASN/ISP and broad geolocation are relatively stable, while security flags can change more frequently. Cache results per IP with your preferred TTL and selectively refresh security fields more often if your risk model depends on them.
Timestamps and timezones
The timezone field is an IANA name (for example, America/Los_Angeles). Use it to render local times, convert scheduled job windows, and normalize analytics. Store both UTC timestamps and the provided timezone to reproduce user-facing times.
Error handling and partial failures
Check the status field per result. Your code should skip or quarantine rows that are not "success" without failing the whole batch. Maintain observability by counting non-success rows and alerting if this count crosses a threshold.
Throughput and retry strategy
Use a bounded concurrency model in your job runners to keep memory predictable and avoid thundering herds. For transient network issues, retry with exponential backoff and jitter. Rebuild batches for retries using only the IPs that failed.
Data normalization
Normalize countryCode and region to canonical uppercase strings in storage. Keep both as and isp/org fields as provided so you can analyze differences between ASN registration and service branding.
Security signals: proxy, VPN, cloud-provider flags
Three booleans in security help with straightforward policy rules:
- is_proxy: consider flagging or adding friction to flows prone to abuse.
- is_vpn: useful for compliance gates or tiered trust decisions.
- is_cloud_provider: high-signal for scripted traffic; tune your limits and CAPTCHA usage accordingly.
Avoid binary allow/deny decisions purely on one flag; combine with user behavior and rate patterns for fewer false positives.
Rollout steps for pipelines and services
- Start with the fixture body to validate serialization and auth.
- Wrap the call in a small client module that executes POST /api/batch-ip, sets Authorization: Bearer YOUR_KEY, and parses json.results.
- Standardize a result schema (ip, location fields, timezone, ISP/ASN, and security flags) and write it to your datastore.
- Implement per-row status inspection and retry only the failed IPs in small follow-up batches.
- Add metrics: success rate, average latency per batch, and distribution of security flags. Track your n+1 credit consumption.
Operational tips for queues, tasks, and dashboards
- Queues: group up to 1024 IPs per message for peak efficiency; if your upstream emits at random sizes, add a brief buffering window to accumulate IPs.
- Service limits: budget calls based on the n+1 model; measure the real-world average batch size to forecast usage against your plan.
- Dashboards: render countryCode and as side by side for quick anomaly spotting; surface vpn/proxy/cloud as separate counters.
- Storage: index by ip and by countryCode for geo-segmented reports; store timezone for on-demand conversions.
CLI and workflow automation
For shell-centric workflows, the official cURL shown above is sufficient to wire into cron or CI steps. Make sure your CI masks the Authorization header and that your payload file only includes valid IPs separated by commas and wrapped as a JSON array.
MCP endpoint for downstream integrations
If you integrate through a control plane or orchestrator that calls MCP-style targets, you can reference the platform endpoint: MCP. This is useful when consolidating your API calls across environments. Consult the Documentation for any MCP-specific considerations in your setup.
Testing plan using the documented fixture
Implement a test that posts the exact fixture body and asserts that:
- HTTP 2xx is returned and response parses as JSON.
- json.results is an array and contains objects with a status field.
- Each object contains query and the expected core keys (country, countryCode, lat, lon, timezone, isp, org, as, security).
Include one negative test where you intentionally add a malformed entry to confirm your per-row status handling. Keep this test out of production pipelines and revert to valid-only inputs for live runs.
Monitoring and alerting
Set up monitors for:
- Batch failure ratio: non-success rows / total rows per batch.
- Latency: p95 per batch for SLOs; alert on sustained degradations.
- Usage: daily credits consumed derived from batch_size + 1 per request.
Emit structured logs that include ip, countryCode, as, and security flags to support triage, and keep PII policies in mind if combining with user records.
Common pitfalls and how to avoid them
- Mixing endpoints: do not substitute single-IP endpoints into batch workflows; keep POST /api/batch-ip throughout.
- Over-batching: very large batches reduce overhead but can amplify retry costs if a network blip occurs. Tune batch size to your reliability goals.
- Dropping query: always read row.query to map results back to inputs.
- Assuming static security: refresh high-risk segments more frequently than bulk archives.
FAQ
How many IPs can I send per request?
Up to 1024 IPs in a single JSON array.
How are credits calculated for batch requests?
Credits equal n+1, where n is the number of IPs you submit.
Which fields should I store for geolocation and security?
At minimum: query, country, countryCode, region, regionName, city, zip, lat, lon, timezone, isp, org, as, and security.is_proxy/is_vpn/is_cloud_provider.
How do I authenticate?
Send Authorization: Bearer YOUR_KEY and Content-Type: application/json.
Is there a trial?
Yes, the trial is 7 days or 50 requests. The Basic plan is $29.99/mo.
Get access and start shipping
Set up your key, paste the official cURL, and wire the JavaScript example into your job runner. To create your account and get an API key, go to Register. For parameter and field references, see the Documentation, and if you integrate via a control plane, check MCP.
