IPyAPI
A modern Python client library for the ipapi.co IP geolocation API. Built with httpx, full async support, automatic retries, and optional Pydantic v2 models.
Features
- Sync & Async — both
IPyAPIandAsyncIPyAPIclients - Typed returns —
ReturnType.OBJECT(dataclass),ReturnType.DICT, orReturnType.PYDANTIC - Optional Pydantic v2 — install with
ipyapi[pydantic]to get validated Pydantic models - Batch lookups —
get_batch()for multiple IPs (async usesasyncio.gather) - Auto retry — exponential backoff on 429 rate limit responses
- IP validation — client-side check before any network request
- Complete API coverage — all fields, all response formats (JSON, XML, CSV, YAML, JSONP)
- Full type hints —
@overloadsignatures for precise IDE inference - Python 3.10+
Installation
pip install ipyapi
# or
uv add ipyapi
With optional Pydantic support:
pip install 'ipyapi[pydantic]'
# or
uv add 'ipyapi[pydantic]'
Quick Start
Synchronous
from ipyapi import IPyAPI
with IPyAPI() as client:
location = client.get_location("8.8.8.8")
print(f"{location.city}, {location.country_name}")
# Mountain View, United States
Asynchronous
import asyncio
from ipyapi import AsyncIPyAPI
async def main():
async with AsyncIPyAPI() as client:
location = await client.get_location("8.8.8.8")
print(f"{location.city}, {location.country_name}")
asyncio.run(main())
Usage Examples
Return Types
from ipyapi import IPyAPI, ReturnType
with IPyAPI() as client:
# Default — returns IPLocation dataclass
location = client.get_location("8.8.8.8")
print(location.country_name)
# As dict
data = client.get_location("8.8.8.8", return_type=ReturnType.DICT)
print(data["country_name"])
# As Pydantic model (requires ipyapi[pydantic])
model = client.get_location("8.8.8.8", return_type=ReturnType.PYDANTIC)
print(model.country_name)
Batch Lookup
with IPyAPI() as client:
results = client.get_batch(["8.8.8.8", "1.1.1.1"])
for r in results:
print(f"{r.ip} — {r.org}")
Async batch runs concurrently via asyncio.gather:
async with AsyncIPyAPI() as client:
results = await client.get_batch(["8.8.8.8", "1.1.1.1"])
Retry Configuration
# Retry up to 5 times on 429, with 2s base backoff (sleeps 2, 4, 8, 16, 32s)
with IPyAPI(max_retries=5, retry_backoff=2.0) as client:
location = client.get_location("8.8.8.8")
Single Fields
with IPyAPI() as client:
print(client.get_ip())
print(client.get_city("8.8.8.8"))
print(client.get_country("8.8.8.8"))
print(client.get_country_name("8.8.8.8"))
print(client.get_timezone("8.8.8.8"))
print(client.get_currency("8.8.8.8"))
print(client.get_asn("8.8.8.8"))
print(client.get_org("8.8.8.8"))
# Any field by name
postal = client.get_field("postal", "8.8.8.8")
Raw Response Formats
with IPyAPI() as client:
json_data = client.get_location_raw("8.8.8.8", format="json")
xml_data = client.get_location_raw("8.8.8.8", format="xml")
csv_data = client.get_location_raw("8.8.8.8", format="csv")
yaml_data = client.get_location_raw("8.8.8.8", format="yaml")
Error Handling
from ipyapi import IPyAPI
from ipyapi.exceptions import InvalidIPAddressError, RateLimitError, IPyAPIError
with IPyAPI() as client:
try:
location = client.get_location("not-an-ip")
except InvalidIPAddressError:
print("Invalid IP address")
except RateLimitError:
print("Rate limited — retries exhausted")
except IPyAPIError as e:
print(f"API error {e.status_code}: {e.message}")
API Reference
Client constructors
IPyAPI(
api_key=None, # API key for paid plans
base_url="https://ipapi.co",
timeout=10.0, # seconds
max_retries=3, # retries on 429
retry_backoff=1.0, # base backoff in seconds (sleeps backoff * 2^attempt)
)
AsyncIPyAPI accepts the same parameters.
Methods
| Method | Returns |
|---|---|
get_location(ip=None, return_type=ReturnType.OBJECT) |
IPLocation / dict / PydanticIPLocation |
get_batch(ips, return_type=ReturnType.OBJECT) |
list[IPLocation] / list[dict] / list[PydanticIPLocation] |
get_field(field, ip=None) |
str |
get_location_raw(ip=None, format="json") |
str |
get_ip() |
str |
get_city(ip=None) |
str |
get_country(ip=None) |
str |
get_country_name(ip=None) |
str |
get_timezone(ip=None) |
str |
get_currency(ip=None) |
str |
get_asn(ip=None) |
str |
get_org(ip=None) |
str |
IPLocation fields
ip, network, version, city, region, region_code, country, country_name, country_code, country_code_iso3, country_capital, country_tld, continent_code, in_eu, postal, latitude, longitude, timezone, utc_offset, country_calling_code, currency, currency_name, languages, country_area, country_population, asn, org, hostname, latlong
Exceptions
All inherit from IPyAPIError:
| Exception | Trigger |
|---|---|
InvalidIPAddressError |
Invalid IP format (raised client-side) |
ReservedIPAddressError |
Reserved/private IP (raised by API) |
BadRequestError |
400 |
ForbiddenError |
403 |
NotFoundError |
404 |
MethodNotAllowedError |
405 |
RateLimitError |
429 after all retries exhausted |
Development
git clone https://github.com/wihlarkop/ipyapi.git
cd ipyapi
uv sync --all-extras
uv run pytest # run tests
uv run pytest --cov=ipyapi --cov-report=html # with coverage
uv run ruff check ipyapi/ tests/ # lint
uv run ruff format ipyapi/ tests/ # format
Rate Limits
- Free tier: 1,000 requests/day, 30 requests/minute
- For higher limits see ipapi.co pricing
License
MIT — see LICENSE for details.
Links
- API docs: ipapi.co/api
- PyPI: pypi.org/project/ipyapi
- Source: github.com/wihlarkop/ipyapi
- Issues: github.com/wihlarkop/ipyapi/issues
Release files for ipyapi 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| ipyapi-0.2.0.tar.gz | 52.3 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ipyapi-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 65.4 kB
Release files / ipyapi-0.2.0.tar.gz
| Download URL | ipyapi-0.2.0.tar.gz |
|---|---|
| Size | 52.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c800199d4be2fa0dce0e40a24a6ef3eb4dc52543a2c3f78d8ba71e50464ac667
|
|
BLAKE2b-256 checksum How to use checksums |
c3d4b9a119fb4221410cc9558429f3e7d0d440351c53a16622c7d16641968912
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Release files / ipyapi-0.2.0-py3-none-any.whl
| Download URL | ipyapi-0.2.0-py3-none-any.whl |
|---|---|
| Size | 13.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ec407452dd1f5304a96106df2afdb924d60755a2eeef5bd2f331f75272b35120
|
|
BLAKE2b-256 checksum How to use checksums |
4f73ae3748659179c4451e52b814956c12ef088d3f4cf090a016c0d8c591fb48
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|