The ipkiwi API
Three GET endpoints, no key, no sign-up. They run on the same Cloudflare edge server that accepts your connection, so the answer typically comes back in a few dozen milliseconds wherever you are.
Endpoints
| Endpoint | Returns | Cache |
|---|---|---|
/api/me | Everything, as JSON | private, no-store |
/api/me.txt | The bare address, as plain text | private, no-store |
/api/ptr | Reverse DNS for your address, or any address | public, max-age=3600 |
Only GET and HEAD are accepted; anything else returns 405. An unknown
path under /api/ returns 404.
/api/me
curl https://ipkiwi.com/api/me
{
"ip": "203.0.113.42",
"version": "IPv4",
"location": {
"country": "DE",
"countryName": "Germany",
"city": "Berlin",
"region": "Berlin",
"regionCode": "BE",
"postalCode": "10117",
"continent": "EU",
"latitude": "52.52437",
"longitude": "13.41053",
"timezone": "Europe/Berlin",
"isEu": true
},
"network": {
"asn": 3320,
"as": "AS3320",
"organization": "Deutsche Telekom AG",
"type": "residential"
},
"connection": {
"httpProtocol": "HTTP/3",
"tlsVersion": "TLSv1.3",
"tlsCipher": "AEAD-AES128-GCM-SHA256"
},
"edge": { "colo": "FRA", "city": "Frankfurt" }
}
network.type is one of residential, hosting, vpn or unknown. It is a
heuristic over the autonomous system the address belongs to, not a verdict —
useful for telling a home line from a data centre, not for blocking anyone.
Fields that the edge could not determine come back as empty strings rather than disappearing, so the shape is stable.
/api/me.txt
For shell scripts, where parsing JSON is more trouble than it is worth:
curl -s https://ipkiwi.com/api/me.txt
# 203.0.113.42
/api/ptr
Reverse DNS, resolved through Cloudflare’s public resolver at request time. Without a parameter it looks up your own address:
curl -s 'https://ipkiwi.com/api/ptr?ip=8.8.8.8'
{ "ip": "8.8.8.8", "hostnames": ["dns.google"], "hostname": "dns.google" }
hostname is the first entry of hostnames, or null when the operator
published no record — which plenty do not. An address that is not valid IPv4
or IPv6 returns 400 with {"error": "invalid_ip"}. This is the one endpoint
that accepts an arbitrary address, and the one with a cache: an hour, because
PTR records rarely move.
CORS, caching and errors
Every response sends Access-Control-Allow-Origin: *, so calling from a
browser needs no proxy.
The two /api/me endpoints are private, no-store: the answer describes the
caller, so it must never be held by a shared cache. Do not put a CDN in front
of them expecting a hit.
Errors are JSON with an error key: invalid_ip (400) and
method_not_allowed (405).
What this does not do
It describes the address the request came from. There is no endpoint that
geolocates an arbitrary address — /api/ptr resolves names for any address,
but country, city and network are only ever reported for the caller. If you
need bulk geolocation, a licensed database is the honest answer.
Fair use
Cache results instead of polling. If you are rendering a page per visitor, one call per page view is the expected pattern; a loop that calls it every second is not. Endpoints may change or be withdrawn, so cache what you depend on.
No request to any of these is logged. Nothing is stored, so there is nothing to export, breach or hand over.
Frequently asked questions
Do I need an API key?
No. There is no key, no sign-up and no account. Send the request and you get the answer.
What is the rate limit?
There is no published limit for ordinary use. Cache results rather than polling, and do not build something whose load would deny others the use of it. Traffic that threatens availability may be rate-limited or blocked.
Can I use it from the browser?
Yes. Every endpoint sends `Access-Control-Allow-Origin: *`, so a fetch from any origin works.
Can I use it in a commercial product?
Yes. The terms allow any lawful purpose, personal or commercial. Attribution is welcome but not required.
Do you log API requests?
No. The code runs for the length of one request and keeps nothing afterwards — the same as for the pages. There is no database and no request log.