公開 JSON API

IPKit HTTP API

この接続の公開 IP、または任意の IPv4/IPv6 を安定した ipkit.v1 JSON で返します。ベース https://ipkit.dev。API キー不要。

IPKit は Cloudflare エッジで動作します。HTML と JSON は同じ照会パイプラインです。実装どおりの HTTP API を説明します。SLA はなく、合理的な利用をお願いします。

ベース URL とエンドポイント

すべて https://ipkit.dev 上です。パスは大小文字を区別します。IPv6 はシェルによっては引用またはパーセントエンコードが必要です。

GET, HEAD /
Current public IP of the connecting client. Browsers (Accept: text/html) get the homepage HTML; curl and most scripts get JSON. Force JSON with ?format=json or use /api/my-ip.
GET, HEAD /{ip}
Look up a specific public IPv4 or IPv6 address. Always JSON, even in a browser. Example: /8.8.8.8. Invalid syntax returns 400 INVALID_IP. Private and reserved ranges return 400 RESERVED_IP. Requires the Worker secret IPREGISTRY_API_KEY; otherwise 503 LOOKUP_UNAVAILABLE.
GET, HEAD /api/my-ip
Current public IP, always JSON. This is the URL the website itself fetches.
GET, HEAD /api/ip/{ip}
Look up a specific public address, always JSON. Same validation and provider requirement as /{ip}. Encode the address (especially IPv6) when building the path, for example /api/ip/8.8.8.8.
OPTIONS /, /{ip}, /api/my-ip, /api/ip/{ip}
CORS preflight on every public JSON lookup URL. Returns 204 with Access-Control-Allow-Origin: *, Allow-Methods GET, HEAD, OPTIONS, and Access-Control-Max-Age 86400.

Lookup routes accept GET, HEAD, and OPTIONS. HEAD returns the same status and headers with an empty body. POST and other methods are not part of the lookup API. Clients do not send an API key; arbitrary lookups still need the operator-configured IPREGISTRY_API_KEY Worker secret.

There is no plaintext-only route and no endpoint that returns a single field. Read ip from the ipkit.v1 object (for example jq -r .ip). Lookups of private, loopback, link-local, CGNAT, multicast, unspecified, documentation, and other reserved IPv4/IPv6 ranges (including IPv4-mapped IPv6 such as ::ffff:10.0.0.1) return 400 RESERVED_IP. Current-IP detection of this connection is not subject to that check.

コンテンツネゴシエーション

HTML と JSON を切り替えるのは / だけです。/{ip} と /api/* は常に JSON です。

?format=json
JSON ipkit.v1, even when Accept includes text/html.
?format=html
HTML homepage, even when the client would otherwise get JSON (for example curl).
Accept includes text/html
HTML homepage. Typical browsers send this.
HTML crawler User-Agent
Googlebot, Bingbot, Baidu, Sogou, and 360Spider receive HTML on / so they index the page instead of JSON.
Otherwise
JSON. curl’s default Accept is */*, and fetch() defaults to */*, so both receive JSON from / without extra headers.

ipkit.v1 レスポンススキーマ

Successful lookups return Content-Type application/json; charset=utf-8, pretty-printed with two-space indent and a trailing newline. Field names stay in English. null means that value was not supplied. Locations are network estimates, not a street address or identity.

source is "ipregistry" when the configured intelligence provider succeeded. It is "cloudflare" when the record is built from Cloudflare request metadata (used for the current IP if the provider is missing or fails). Cloudflare metadata describes the connecting client only; it is never used as geolocation for a different target IP. Cloudflare-sourced records fill location.countryCode from request.cf.country or CF-IPCountry and location.country from that code when a name is known. Several network fields stay null, security flags are null, and security.risk is "unknown". If IPREGISTRY_API_KEY is unset, arbitrary lookups return 503 instead of guessing the caller’s country.

schema
Always "ipkit.v1" so clients can detect breaking changes.
ip
The public address that was detected (current connection) or requested (lookup).
type
"IPv4" or "IPv6".
source
"ipregistry" when the configured intelligence provider succeeded; "cloudflare" when the record is built from Cloudflare edge metadata only.
location.continent
Continent name when the provider supplies one; otherwise null.
location.country
Country name. For source=ipregistry, the provider’s name. For source=cloudflare, the English name derived from Cloudflare’s ISO country code (request.cf.country or CF-IPCountry). Null when the code is missing, XX (unknown), T1 (Tor), or otherwise unnamed.
location.countryCode
ISO 3166-1 alpha-2 code when known. Cloudflare supplies this for the connecting client. XX is stored as null. T1 (Tor) is kept as T1.
location.region
Region or state name at network granularity, or null.
location.regionCode
Region code when available, or null.
location.city
City at network granularity when the provider has one, or null.
location.postalCode
Postal code when the provider has one, or null. Not a street address.
location.latitude
Estimated latitude as a number, or null.
location.longitude
Estimated longitude as a number, or null.
location.timezone
IANA timezone id tied to the geolocation guess, or null.
network.asn
Autonomous system as "ASnnnn", or null.
network.organization
ISP or organization name for that ASN, or null.
network.domain
Network or company domain when the provider has one, or null.
network.route
Announced prefix/route when available, or null.
network.usage
Connection or company usage type from the provider (for example hosting), or null.
network.carrier
Mobile carrier name when the provider has one, or null.
security.proxy
Whether the provider flags a proxy; null when unknown (typical for source=cloudflare).
security.vpn
Whether the provider flags a VPN, or null.
security.tor
Whether the provider flags a Tor exit, or null.
security.relay
Whether the provider flags a privacy relay, or null.
security.cloud
Whether the provider flags a cloud provider, or null.
security.threat
Whether the provider flags a threat, or null. A signal, not proof.
security.risk
"low", "medium", "high", or "unknown". Derived from provider flags when present; "unknown" for cloudflare-sourced records. Not a fraud score and not sole proof for blocking.

Example response

Illustrative ipkit.v1 object for 8.8.8.8. Values change with the address and data source; clients must tolerate nulls.

{
  "schema": "ipkit.v1",
  "ip": "8.8.8.8",
  "type": "IPv4",
  "source": "ipregistry",
  "location": {
    "continent": "North America",
    "country": "United States",
    "countryCode": "US",
    "region": "California",
    "regionCode": "CA",
    "city": "Mountain View",
    "postalCode": null,
    "latitude": 37.386,
    "longitude": -122.0838,
    "timezone": "America/Los_Angeles"
  },
  "network": {
    "asn": "AS15169",
    "organization": "Google LLC",
    "domain": "google.com",
    "route": "8.8.8.0/24",
    "usage": "hosting",
    "carrier": null
  },
  "security": {
    "proxy": false,
    "vpn": false,
    "tor": false,
    "relay": false,
    "cloud": true,
    "threat": false,
    "risk": "medium"
  }
}

エラーとステータスコード

Failures return JSON { "error": string, "code": string } with Cache-Control: no-store. error is a human-readable message; code is a stable machine token.

400 INVALID_IP
The path is not a syntactically valid IPv4 or IPv6 address. error is "Invalid IP address."
400 RESERVED_IP
The target on /{ip} or /api/ip/{ip} is a private, loopback, link-local, CGNAT, multicast, unspecified, documentation, or other reserved IPv4/IPv6 address, including IPv4-mapped IPv6 (for example ::ffff:10.0.0.1). error is "Private or reserved IP address." Current-IP GET / and /api/my-ip are not rejected this way.
429 RATE_LIMITED
The connecting client IP exceeded the lookup limit. error is "Too many lookups. Please retry in one minute." Retry-After is 60.
502 LOOKUP_UNAVAILABLE
The intelligence provider failed or timed out (about 6 seconds). error is "The IP data provider is temporarily unavailable."
503 LOOKUP_UNAVAILABLE
For /{ip} and /api/ip/{ip} this usually means the Worker secret IPREGISTRY_API_KEY is missing or empty on the Cloudflare account that serves ipkit.dev. error is then "IP intelligence is not configured for arbitrary lookups." That is operator configuration, not a client error. Set the secret in the dashboard (Workers & Pages → ipkit → Settings → Variables and Secrets) or with wrangler secret put IPREGISTRY_API_KEY. Current-IP GET / and /api/my-ip still succeed from Cloudflare metadata. The same status and code are also used when Ipregistry rate-limits IPKit; then error is "The IP data provider is temporarily unavailable."
500 LOOKUP_UNAVAILABLE
Unexpected lookup failure. error is "Unexpected lookup failure."

CORS

エラーを含むすべての JSON 照会応答に Access-Control-Allow-Origin: * が付きます。OPTIONS プリフライト (204) は /、/{ip}、/api/my-ip、/api/ip/{ip} で、許可メソッドは GET, HEAD, OPTIONS、Max-Age 86400。/ の HTML は CORS JSON ではありません。

レート制限

接続元クライアント IP あたり 60 秒で 300 リクエスト。SLA はありません。無料の公開ツールであり、契約 API ではありません。

キャッシュ

Current-IP JSON (negotiated / and /api/my-ip) is Cache-Control: private, no-store so one client’s address is not reused for another. Specific-IP lookups (/{ip} and /api/ip/{ip}) are Cache-Control: public, max-age=300, s-maxage=3600, stale-while-revalidate=86400. Error responses are no-store. / JSON also varies on Accept and CF-Connecting-IP.

コピー用の例

No authentication. HTTPS only. Parse schema and handle nulls and error objects.

Current public IP (curl)

curl https://ipkit.dev

Look up an address

curl https://ipkit.dev/8.8.8.8

IPv6 in the path (quote colons)

curl "https://ipkit.dev/2001:4860:4860::8888"

Always-JSON current IP

curl https://ipkit.dev/api/my-ip

JavaScript fetch

const response = await fetch('https://ipkit.dev', {
  headers: { Accept: 'application/json' },
});
const data = await response.json();
console.log(data.ip, data.location.countryCode);

Python

import json, urllib.request

with urllib.request.urlopen('https://ipkit.dev') as response:
    data = json.load(response)
print(data['ip'], data['location']['countryCode'])

Shell one-liner (scripts / DDNS)

curl -sS https://ipkit.dev | jq -r .ip

プライバシー

照会のため、対象アドレスと通常のリクエストメタデータを Cloudflare エッジで処理します。訪問者 IP のアプリ DB はありません。位置はネットワーク推定です。プライバシーポリシーを参照してください。

プライバシーポリシー

FAQ

API キーは必要?

不要です。公開 HTTPS URL に GET してください。

IP 文字列だけ欲しい

text/plain はありません。JSON を解析: curl -sS https://ipkit.dev | jq -r .ip

ブラウザで / が HTML な理由は?

Accept に text/html が含まれるため。?format=json か /api/my-ip を使ってください。

プライベートアドレスは?

不可。/{ip} と /api/ip/{ip} は私有・予約範囲を 400 RESERVED_IP で拒否します。GET / と /api/my-ip は接続元クライアントを返します。

/8.8.8.8 が 503 になる理由は?

「IP intelligence is not configured for arbitrary lookups.」は、ipkit.dev を配信する Cloudflare アカウントに Worker シークレット IPREGISTRY_API_KEY が無いことを意味します。現在 IP の検出は引き続き動きます。