# IP Geo 📍 — IP Geolocation Lookup (Batch) (`perryay/ip-geo`) Actor

Multi-provider IP geolocation with batch support and automatic fallback. Look up 1-50 IPs in a single run. Returns city, country, ISP, lat/lon, timezone, and org data.

- **URL**: https://apify.com/perryay/ip-geo.md
- **Developed by:** [Perry AY](https://apify.com/perryay) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.015 / actor start

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## IP Geo 📍 — IP Geolocation Lookup (Batch)

**Multi-provider IP address geolocation with automatic fallback, batch support, and rich network intelligence.**

Knowing where an IP address is geographically located and who owns it is fundamental to security analysis, content localization, traffic analytics, and fraud detection. **IP Geo** queries multiple geolocation providers in priority order with automatic fallback, returning structured data that includes city, country, region, ISP, organization, AS number, latitude/longitude coordinates, timezone, and postal code — all in a single API call.

Look up a single IP, batch up to 50 IPs in one run, or auto-detect the caller's own IP by leaving the input blank. Two providers (ip-api.com → ipinfo.io) with transparent fallback ensure maximum uptime and geographic coverage.

---

### ✨ Features

- **Batch IP lookup** — Resolve 1 to 50 IP addresses in a single actor run using a dedicated batch endpoint for maximum throughput
- **Multi-provider architecture** — Primary provider (ip-api.com) with automatic fallback to secondary provider (ipinfo.io) if the first fails or returns incomplete data
- **Auto-detect caller IP** — Leave the `ip` field blank and the actor automatically detects and geolocates the requesting IP address
- **Rich geographic data** — Returns city, country name, country code, region/state, latitude, longitude, timezone, and postal/zip code
- **Network intelligence** — ISP name, organization name, and AS (Autonomous System) number for every resolved IP
- **Provider transparency** — Every result includes a `source` field indicating which provider served the data, so you always know the origin
- **Configurable provider priority** — Customize which providers to query and in what order via the `providers` input array
- **Performance metrics** — Each result includes `elapsed_ms` (response time in milliseconds) so you can monitor lookup latency
- **Graceful error handling** — Individual IP failures never block the entire batch; failed lookups return error details alongside successful ones
- **Summary statistics** — Batch mode appends a `_summary` row with total count, success count, and total elapsed time

### 🚀 Quick Start

#### Auto-detect (no input required)

Simply run the actor with an empty input — it auto-detects the caller's IP and returns its geolocation data.

**Input:**
```json
{}
````

#### Single IP Lookup

**Input:**

```json
{
  "ip": "8.8.8.8"
}
```

**Response:**

```json
{
  "query_ip": "8.8.8.8",
  "ip": "8.8.8.8",
  "city": "Mountain View",
  "country": "United States",
  "country_code": "US",
  "region": "California",
  "isp": "Google LLC",
  "org": "Google LLC",
  "as": "AS15169 Google LLC",
  "lat": 37.4056,
  "lon": -122.0775,
  "timezone": "America/Los_Angeles",
  "zip": "94043",
  "source": "ip-api.com",
  "success": true,
  "timestamp": 1712345678.123,
  "elapsed_ms": 45.2,
  "auto_detected": false
}
```

#### Batch IP Lookup (up to 50)

**Input:**

```json
{
  "ips": [
    "8.8.8.8",
    "1.1.1.1",
    "208.67.222.222",
    "185.199.108.153",
    "151.101.1.140"
  ]
}
```

Each IP returns its own result row. A `_summary` row is appended with aggregate statistics.

#### Custom Provider Priority

**Input:**

```json
{
  "ip": "8.8.8.8",
  "providers": ["ipinfo", "ip-api"]
}
```

This queries ipinfo.io first, falling back to ip-api.com only if ipinfo fails.

### 📋 Input Parameters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `ip` | string | `""` (auto-detect) | Single IP address to look up. Leave empty to auto-detect the caller's IP. |
| `ips` | array | `[]` | Array of IP addresses for batch lookup (up to 50). Overrides `ip` when both are provided. |
| `providers` | array | `["ip-api", "ipinfo"]` | Provider priority order. First available provider in the list serves the result. |

#### Provider Reference

| Provider Key | Service | Rate Limit | Coverage | Fields |
|-------------|---------|------------|----------|--------|
| `ip-api` | ip-api.com | 45 req/min (unlimited with paid) | Global | City, country, region, ISP, org, AS, lat/lon, timezone, zip |
| `ipinfo` | ipinfo.io | 50K req/month (free tier) | Global | City, country, region, org, lat/lon, timezone, postal |

### 📤 Output Format

Each geolocation lookup produces one result row with the following fields:

| Field | Type | Description |
|-------|------|-------------|
| `ip` | string | The IP address that was queried |
| `query_ip` | string | Original query input (may include non-resolved IPs) |
| `city` | string | City name (e.g. "Mountain View") |
| `country` | string | Full country name (e.g. "United States") |
| `country_code` | string | ISO 3166-1 alpha-2 country code (e.g. "US") |
| `region` | string | State, province, or region name (e.g. "California") |
| `isp` | string | Internet Service Provider name |
| `org` | string | Organization name |
| `as` | string | Autonomous System number and name (e.g. "AS15169 Google LLC") |
| `lat` | number | Latitude coordinate |
| `lon` | number | Longitude coordinate |
| `timezone` | string | IANA timezone identifier (e.g. "America/Los\_Angeles") |
| `zip` | string | Postal/ZIP code (when available) |
| `source` | string | Provider that served the data: `ip-api.com` or `ipinfo.io` |
| `success` | boolean | Whether the lookup succeeded |
| `error` | string | Error message if the lookup failed |
| `errors` | array | List of per-provider errors with `provider` and `error` fields |
| `auto_detected` | boolean | True if the IP was auto-detected from the caller |
| `elapsed_ms` | number | Response time in milliseconds |
| `timestamp` | number | Unix timestamp of when the lookup was performed |

A `_summary` row is appended in batch mode with `total`, `success_count`, `elapsed_ms`, and `batch: true`.

### 📖 Usage Examples

#### cURL (Apify API)

```bash
## Single IP lookup
curl -X POST "https://api.apify.com/v2/acts/perryay~ip-geo/runs" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -d '{"ip": "8.8.8.8"}'

## Batch IP lookup
curl -X POST "https://api.apify.com/v2/acts/perryay~ip-geo/runs" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -d '{"ips": ["8.8.8.8", "1.1.1.1"]}'
```

#### Python (Apify SDK)

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

## Single IP lookup
result = client.actor("perryay~ip-geo").call(
    run_input={"ip": "8.8.8.8"}
)
dataset = client.dataset(result["defaultDatasetId"]).list_items()
for item in dataset.items:
    print(f"{item['ip']} → {item['city']}, {item['country']} ({item['isp']})")

## Batch IP lookup
result = client.actor("perryay~ip-geo").call(
    run_input={"ips": ["8.8.8.8", "1.1.1.1", "208.67.222.222"]}
)
dataset = client.dataset(result["defaultDatasetId"]).list_items()
for item in dataset.items:
    if item.get("_summary"):
        print(f"Summary: {item['success_count']}/{item['total']} successful")
    else:
        print(f"{item['ip']} → {item.get('city', 'N/A')}, {item.get('country', 'N/A')}")
```

#### JavaScript / Node.js (Apify SDK)

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });

// Single IP lookup
const result = await client.actor('perryay~ip-geo').call({
  ip: '8.8.8.8'
});
const { items } = await client.dataset(result.defaultDatasetId).listItems();
items.forEach(item => {
  if (item._summary) {
    console.log(`Summary: ${item.success_count}/${item.total} successful`);
  } else {
    console.log(`${item.ip} → ${item.city}, ${item.country} (${item.isp})`);
  }
});
```

### 🎯 Use Cases

- **Security threat analysis** — Geolocate suspicious IP addresses from firewall logs, failed login attempts, and web application logs to identify geographic attack patterns and block high-risk regions
- **CDN and edge network optimization** — Map user IP addresses to geographic regions to verify CDN edge node selection, optimize content routing, and ensure regional compliance with data locality requirements
- **Traffic analytics enrichment** — Augment web analytics data with geographic location, ISP, and organization information for detailed audience segmentation and market analysis
- **Fraud detection** — Cross-reference IP geolocation with claimed user locations, shipping addresses, and payment origins to flag mismatches indicative of fraudulent activity
- **Content localization** — Route users to region-specific content, pricing, or legal terms based on their IP's detected country and timezone
- **Network inventory auditing** — Scan your organization's public IP range and automatically document geographic distribution, ISP assignments, and AS membership for asset management
- **API rate limiting by region** — Enforce different rate limits or access policies based on the geographic origin of API requests
- **Compliance verification** — Verify that traffic from regulated regions (e.g., GDPR in Europe, PIPL in China) is properly identified and handled according to local data laws

### ❓ FAQ

**Q: How many IPs can I look up in a single run?**
A: Up to 50 IPs in batch mode via the `ips` array. For individual lookups, use the `ip` field.

**Q: What happens if a provider is down?**
A: The actor automatically falls back to the next provider in the priority list. If ip-api.com fails, it tries ipinfo.io. If all providers fail, the result is marked with `success: false` and the error details are recorded in the `errors` array.

**Q: Is there a rate limit?**
A: ip-api.com allows 45 requests per minute on the free tier (unlimited with paid). ipinfo.io allows 50,000 requests per month on the free tier. For production workloads, consider configuring provider API keys or using a paid tier.

**Q: Do I need an API key?**
A: No. Both bundled providers offer free tiers without API keys for basic lookups. For higher rate limits or premium data, you can configure paid accounts.

**Q: Can I configure custom providers?**
A: The built-in providers (ip-api.com and ipinfo.io) are always available. You can control the priority order via the `providers` array.

**Q: What does the auto-detect feature return?**
A: When you leave the `ip` field blank, the actor detects the IP address of the machine making the API request (your server or the Apify platform) and returns its geolocation data.

**Q: How accurate is the geolocation data?**
A: Accuracy varies by IP and provider. City-level accuracy is typically 80-95% for IPs in densely populated regions. Rural areas and mobile IP ranges may resolve to regional rather than city-level data. ip-api.com claims 99.8% uptime and city-level accuracy for most IPs.

**Q: What ASN data is returned?**
A: When available, the `as` field returns the Autonomous System number and name (e.g., "AS15169 Google LLC"). This is useful for network-level analysis and traffic categorization.

**Q: Can I use this for real-time lookups?**
A: Yes. Typical response times are 30-150ms per IP. Batch mode processes multiple IPs in parallel for faster throughput. For real-time applications, we recommend caching results with a TTL appropriate to your use case.

**Q: Does this work for IPv6 addresses?**
A: Yes. Both ip-api.com and ipinfo.io support IPv6 geolocation. Input validation allows standard IPv4 and IPv6 address formats.

### 🛠 Tips & Best Practices

- **Batch mode for bulk lookups** — Always use the `ips` array instead of calling the actor repeatedly for each IP. Batch mode uses a dedicated batch endpoint that is significantly faster than individual lookups.
- **Cache results aggressively** — IP geolocation data changes infrequently (ISP reassignments, infrastructure moves). Cache results with a 24-48 hour TTL to reduce API calls and improve response times.
- **Provider priority for reliability** — Keep the default provider priority (`ip-api` first, `ipinfo` fallback) unless you have a specific reason to change it. ip-api.com offers faster response times and richer data (AS number, zip code), while ipinfo.io provides reliable fallback coverage.
- **Monitor success rates** — The `_summary` row in batch mode includes `success_count`. If you see persistent failures, consider switching provider priority or adding provider-specific API keys.
- **Combine with other security tools** — IP geolocation is most powerful when combined with other signals. Use this actor in pipelines with IP reputation checks, proxy detection, and threat intelligence feeds.
- **Respect privacy regulations** — IP addresses are considered personal data under GDPR and similar regulations. Ensure you have a lawful basis for processing IP geolocation data and implement appropriate data retention and anonymization policies.
- **Test with known IPs** — Verify provider coverage by testing with IPs you know the location of (e.g., your own public IP, well-known DNS resolvers like 8.8.8.8 and 1.1.1.1).

### ⚙️ How It Works

The actor uses a multi-provider architecture with automatic failover to maximize uptime and coverage:

1. **Input received** — The actor accepts a single IP (`ip`), an array of IPs (`ips`), or auto-detects the caller's IP if both are empty
2. **Provider selection** — The actor iterates through the configured providers list in priority order (`ip-api` → `ipinfo` by default)
3. **Query execution** — For single IPs, each provider is queried sequentially until one succeeds. For batches, a dedicated batch endpoint is used first, with per-IP fallback if the batch request fails
4. **Data parsing** — Each provider's response is parsed through a provider-specific transform function that normalizes field names and extracts all available data points
5. **Result delivery** — Each resolved IP is pushed as a separate dataset item. A `_summary` row is appended in batch mode with aggregate statistics

The fallback chain is transparent: you always know which provider served each result via the `source` field.

### 🔄 Provider Comparison

| Feature | ip-api.com | ipinfo.io |
|---------|-----------|-----------|
| City-level data | ✅ | ✅ |
| Country code | ✅ (ISO alpha-2) | ✅ (ISO alpha-2) |
| Region/State | ✅ | ✅ |
| ISP name | ✅ | ✅ (in `org` field) |
| Organization | ✅ | ✅ |
| AS Number | ✅ | ❌ |
| Latitude/Longitude | ✅ | ✅ |
| Timezone | ✅ | ✅ |
| ZIP/Postal Code | ✅ | ✅ (`postal`) |
| Batch endpoint | ✅ | ❌ |
| Rate limit (free) | 45 req/min | 50K req/month |
| Requires API key | No | No (free tier) |
| Response time | Fast (~30-80ms) | Moderate (~80-200ms) |

### 🗺 Geographic Coverage

Both providers offer global coverage but with varying granularity:

| Region | ip-api.com | ipinfo.io |
|--------|-----------|-----------|
| North America | City-level | City-level |
| Europe | City-level | City-level |
| Asia | City/regional | City/regional |
| South America | City-level | City/regional |
| Africa | Regional/country | Regional/country |
| Oceania | City-level | City-level |

### 📊 Batch Mode Details

When processing multiple IPs via the `ips` array, the actor:

1. Validates each IP address format (IPv4 and IPv6 supported)
2. Sends all valid IPs to the batch endpoint in a single request
3. Falls back to individual lookups per IP if the batch endpoint fails
4. Pushes each result as a separate dataset item
5. Appends a `_summary` row with aggregate statistics

The summary row looks like:

```json
{
  "_summary": true,
  "total": 5,
  "success_count": 4,
  "elapsed_ms": 312.4,
  "batch": true
}
```

***

### 🔗 Related Tools

Check out other developer utilities by [perryay](https://apify.com/perryay):

| Tool | Description |
|------|-------------|
| [JSON Studio](https://apify.com/perryay/json-studio) | Format, validate, transform, and diff JSON data with 8 operation modes |
| [QR Craft](https://apify.com/perryay/qr-craft) | Generate high-quality QR codes in PNG or SVG, batch up to 50 |
| [UUID Lab](https://apify.com/perryay/uuid-lab) | Generate UUID v4/v7, NanoID, Short ID, and ULID identifiers |
| [Domain Intel](https://apify.com/perryay/domain-intel) | WHOIS, DNS, and SSL lookup for domain intelligence |
| [Meta Mate](https://apify.com/perryay/meta-mate) | Extract Open Graph, Twitter Cards, and JSON-LD metadata |
| [IP Geo](https://apify.com/perryay/ip-geo) | Multi-provider IP geolocation with ISP detection |
| [URL Health](https://apify.com/perryay/url-health) | Check URL accessibility, redirects, and SSL health |
| [PW Forge](https://apify.com/perryay/pw-forge) | Generate secure passwords with entropy calculation |
| [TZ Mate](https://apify.com/perryay/tz-mate) | Convert timezones and check DST offsets |
| [Regex Lab](https://apify.com/perryay/regex-lab) | Test and debug regular expressions online |
| [Brand Monitor Lite](https://apify.com/perryay/brand-monitor-lite) | Track brand mentions across multiple URLs |
| [Link Quality Analyzer](https://apify.com/perryay/link-quality-analyzer) | Detect broken links and audit link quality |
| [Mock Data Generator](https://apify.com/perryay/mock-data-generator) | Generate realistic test data for development |
| [HTML to Markdown](https://apify.com/perryay/html-to-markdown) | Convert web pages or HTML to clean Markdown |
| [SSL Cert Inspector](https://apify.com/perryay/ssl-cert-inspector) | Deep SSL/TLS certificate analysis with scoring |

# Actor input Schema

## `ip` (type: `string`):

Single IP address to look up (default: auto-detects caller's IP). Leave empty if using batch mode.

## `ips` (type: `array`):

Multiple IP addresses to look up in a single run (up to 50). Overrides 'ip' if set.

## `providers` (type: `array`):

Geolocation providers to query in order (fallback chain)

## Actor input object example

```json
{
  "ip": "8.8.8.8",
  "ips": [
    "8.8.8.8",
    "1.1.1.1",
    "208.67.222.222"
  ],
  "providers": [
    "ip-api",
    "ipinfo"
  ]
}
```

# Actor output Schema

## `results` (type: `string`):

Per-IP geolocation results in the default dataset

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "ip": "8.8.8.8",
    "ips": [
        "8.8.8.8",
        "1.1.1.1",
        "208.67.222.222"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("perryay/ip-geo").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "ip": "8.8.8.8",
    "ips": [
        "8.8.8.8",
        "1.1.1.1",
        "208.67.222.222",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("perryay/ip-geo").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "ip": "8.8.8.8",
  "ips": [
    "8.8.8.8",
    "1.1.1.1",
    "208.67.222.222"
  ]
}' |
apify call perryay/ip-geo --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=perryay/ip-geo",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "IP Geo 📍 — IP Geolocation Lookup (Batch)",
        "description": "Multi-provider IP geolocation with batch support and automatic fallback. Look up 1-50 IPs in a single run. Returns city, country, ISP, lat/lon, timezone, and org data.",
        "version": "1.0",
        "x-build-id": "sYZINGMf3bpTWeBNp"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/perryay~ip-geo/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-perryay-ip-geo",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/perryay~ip-geo/runs": {
            "post": {
                "operationId": "runs-sync-perryay-ip-geo",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/perryay~ip-geo/run-sync": {
            "post": {
                "operationId": "run-sync-perryay-ip-geo",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "ip": {
                        "title": "IP Address (single)",
                        "type": "string",
                        "description": "Single IP address to look up (default: auto-detects caller's IP). Leave empty if using batch mode.",
                        "default": ""
                    },
                    "ips": {
                        "title": "IP Addresses (batch)",
                        "type": "array",
                        "description": "Multiple IP addresses to look up in a single run (up to 50). Overrides 'ip' if set."
                    },
                    "providers": {
                        "title": "Providers",
                        "type": "array",
                        "description": "Geolocation providers to query in order (fallback chain)",
                        "default": [
                            "ip-api",
                            "ipinfo"
                        ],
                        "items": {
                            "type": "string"
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
