# IP 查询 API — 完整参考（AI 可读单文件版）

Source: https://api.ip.denys.cn/docs
更新时间随站点发布。

## 简介

IP 查询 API（api.ip.denys.cn）提供 IP 归属地查询 API：支持 IPv4 与 IPv6，毫秒级返回国家、省份、城市、运营商等 20+ 个字段；按次计费、仅查询命中（found=true）计费，次数长期有效；注册并完成邮箱验证即送 1,000 次免费额度。

## 接口

- `GET https://api.ip.denys.cn/v1/query?ip=223.5.5.5` — 查询单个 IP（IPv4/IPv6 均可）；省略 ip 参数时查询调用方 IP。
- `POST https://api.ip.denys.cn/v1/query` — 批量查询，请求体 {"ips":["223.5.5.5","119.29.29.29","2400:3200::1"]}，IPv4/IPv6 可混排，单次最多 100 个（超出返回 413 too_many_ips），响应为 {"results":[...]}，顺序与请求一致。

## 鉴权

所有请求携带请求头 `X-API-Key: ipk_your_key`（在 https://api.ip.denys.cn/console 创建，每账号最多 50 个）。
也支持 ?key= 查询参数，但会进入访问日志，不建议使用。

## 返回格式

响应均为 application/json。GET 返回单个对象，POST 返回 {"results":[...]}，每项结构相同：

基础字段：

| 字段 | 类型 | 说明 | 缺省 |
|---|---|---|---|
| ip | string | 查询的 IP（IPv4/IPv6 均原样回显） | 必返回 |
| found | boolean | 是否命中；false 表示未收录（内网/保留地址等），不计费 | 必返回 |
| country | string | 国家或地区 | 必返回 |
| province | string | 省份/州 | 可能为空串 |
| city | string | 城市（已归一化为规范名，如「深圳」→「深圳市」） | 可能为空串 |
| isp | string | 运营商/网络归属 | 可能为空串 |
| country_code | string | ISO 3166-1 alpha-2 国家码，如 CN、US；港澳台统一返回 CN | 必返回 |

各字段是否可能缺失见表的「缺省」列（**必返回** / 可能为空串 / 可能不返回）。
本接口**不会返回 null**，也不用占位值代替缺失信息；「没有这个字段」与「字段是空串」是两种状态。

| 字段 | 类型 | 说明 | 缺省 |
|---|---|---|---|
| is_china_mainland | boolean | 是否中国大陆（港澳台为 false）；合规/路由判断请直接用它 | 必返回 |
| region | string | 地区归类：mainland / hk / mo / tw / overseas | 必返回 |
| continent_code | string | 大洲码：AS/EU/NA/SA/OC/AF/AN | 可能不返回 |
| phone_prefix | string | 国际电话区号（含 +）：大陆 +86、香港 +852、澳门 +853、台湾 +886 | 可能不返回 |
| china_province_code | string | 省级行政区划代码（GB/T 2260），如 浙江省=330000 | 可能不返回 |
| china_city_code | string | 市级行政区划代码（GB/T 2260/国家统计局口径）：地级市 xxx00（抚州市=361000），县级市/市辖区/县为自身 6 位码（瑞安市=330381）；港澳台与已撤并实体不返回 | 可能不返回 |
| province_pinyin | string | 省份拼音，如 jiangxi | 可能不返回 |
| province_short_code | string | 省份简码（GB/T 2260 字母码），如 江西=JX | 可能不返回 |
| province_abbr | string | 省级单字简称，如 江西=赣 | 可能不返回 |
| china_region | string | 国内大区：华北/东北/华东/华中/华南/西南/西北（港澳台不返回） | 可能不返回 |
| city_code | string | 城市拼音，如 抚州=fuzhou | 可能不返回 |
| city_short_code | string | 城市简码，如 抚州=FZ | 可能不返回 |
| city_area_code | string | 城市电话区号，如 抚州=0794 | 可能不返回 |
| timezone | string | IANA 时区名，如 Asia/Shanghai | 可能不返回 |
| asn | number | 自治系统号，如 45102 | 可能不返回 |
| as_org | string | AS 所属组织，如 ALIBABA-CN-NET | 可能不返回 |


IPv4 响应示例：

```json
{
  "ip": "223.5.5.5",
  "found": true,
  "country": "中国",
  "province": "浙江省",
  "city": "杭州市",
  "isp": "阿里",
  "country_code": "CN",
  "is_china_mainland": true,
  "region": "mainland",
  "continent_code": "AS",
  "phone_prefix": "+86",
  "china_province_code": "330000",
  "province_pinyin": "zhejiang",
  "province_short_code": "ZJ",
  "province_abbr": "浙",
  "china_region": "华东",
  "city_code": "hangzhou",
  "city_short_code": "HZ",
  "city_area_code": "0571",
  "china_city_code": "330100",
  "timezone": "Asia/Shanghai",
  "asn": 45102,
  "as_org": "ALIBABA-CN-NET Alibaba US Technology Co., Ltd."
}
```

IPv6 响应示例（字段结构完全相同，仅 ip 不同）：

```json
{
  "ip": "2400:3200::1",
  "found": true,
  "country": "中国",
  "province": "浙江省",
  "city": "杭州市",
  "isp": "阿里",
  "country_code": "CN",
  "is_china_mainland": true,
  "region": "mainland",
  "continent_code": "AS",
  "phone_prefix": "+86",
  "china_province_code": "330000",
  "province_pinyin": "zhejiang",
  "province_short_code": "ZJ",
  "province_abbr": "浙",
  "china_region": "华东",
  "city_code": "hangzhou",
  "city_short_code": "HZ",
  "city_area_code": "0571",
  "china_city_code": "330100",
  "timezone": "Asia/Shanghai",
  "asn": 45102,
  "as_org": "ALIBABA-CN-NET Alibaba US Technology Co., Ltd."
}
```

港澳台说明：香港、澳门、台湾的 IP 统一返回 country=中国、country_code=CN，以 province 区分：香港特别行政区、澳门特别行政区、台湾省（city 为空）。判断是否中国大陆请直接用 is_china_mainland 字段（或 region：mainland/hk/mo/tw/overseas），无需自己维护省份名单；国际电话区号已按地区区分（+86/+852/+853/+886）。

香港示例（注意 phone_prefix 与 region 的差异；城市级字段因数据无城市值而缺省）：

```json
{
  "ip": "203.198.0.1",
  "found": true,
  "country": "中国",
  "province": "香港特别行政区",
  "city": "",
  "isp": "电讯盈科",
  "country_code": "CN",
  "is_china_mainland": false,
  "region": "hk",
  "continent_code": "AS",
  "phone_prefix": "+852",
  "china_province_code": "810000",
  "province_pinyin": "xianggang",
  "province_short_code": "HK",
  "province_abbr": "港",
  "timezone": "Asia/Hong_Kong",
  "asn": 45102,
  "as_org": "ALIBABA-CN-NET Alibaba US Technology Co., Ltd."
}
```

## 计费规则

- 仅查询命中（found=true）计费；未命中、IP 格式非法、服务错误均不计费。
- GET 每次最多计 1 次；POST 批量按响应中 found=true 的个数计费，余额不足扣到 0。
- 每次成功（200）响应带 X-Quota-Remaining 头，为本次扣减后的剩余次数。
- 次数长期有效，不设有效期；不自动扣费，用尽后接口返回 402。

## 定价

| 套餐 | 价格 | 次数 | 单价 |
|---|---|---|---|
| 入门 | ¥5 | 5,000 次 | 0.0010 元/次 |
| 标准 | ¥20 | 30,000 次 | 0.0007 元/次 |
| 专业 | ¥50 | 100,000 次 | 0.0005 元/次 |
| 旗舰 | ¥100 | 250,000 次 | 0.0004 元/次 |

## 限流与错误码

每个 API Key 约 50 次/秒（429）。错误响应均为 JSON {"error","message"}：

| HTTP 状态 | error | 说明 |
|---|---|---|
| 401 | unauthorized | 缺少或无效的 API Key |
| 402 | quota_exhausted | 次数已用完，请充值 |
| 403 | key_disabled | API Key 已被禁用 |
| 404 | not_found | 路径不存在，仅开放 /v1/query 与 /v1/asn/as<asn> |
| 405 | method_not_allowed | 仅支持 GET/POST 查询 |
| 429 | rate_limited | 请求过于频繁，请降低调用频率 |
| 502 | upstream_error | 服务暂时不可用，请稍后重试 |

## 调用示例

**curl**

```
# 单个查询
curl 'https://api.ip.denys.cn/v1/query?ip=223.5.5.5' -H 'X-API-Key: ipk_your_key'

# IPv6 查询
curl 'https://api.ip.denys.cn/v1/query?ip=2400:3200::1' -H 'X-API-Key: ipk_your_key'

# 批量查询
curl -X POST 'https://api.ip.denys.cn/v1/query' \
  -H 'X-API-Key: ipk_your_key' \
  -H 'Content-Type: application/json' \
  -d '{"ips":["223.5.5.5","119.29.29.29"]}'
```

**JavaScript**

```
const res = await fetch('https://api.ip.denys.cn/v1/query?ip=223.5.5.5', {
  headers: { 'X-API-Key': 'ipk_your_key' },
})
const data = await res.json()
console.log('剩余次数:', res.headers.get('X-Quota-Remaining'))
console.log(data)
```

**Python**

```
import requests

res = requests.get(
    "https://api.ip.denys.cn/v1/query",
    params={"ip": "223.5.5.5"},
    headers={"X-API-Key": "ipk_your_key"},
)
print(res.json())
print("剩余次数:", res.headers.get("X-Quota-Remaining"))
```

**PHP**

```
<?php
$ch = curl_init('https://api.ip.denys.cn/v1/query?ip=223.5.5.5');
curl_setopt_array($ch, [
    CURLOPT_HTTPHEADER     => ['X-API-Key: ipk_your_key'],
    CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
echo $data['country'], ' ', $data['province'], ' ', $data['city'], PHP_EOL;
```

**Go**

```
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
)

func main() {
	req, _ := http.NewRequest(http.MethodGet, "https://api.ip.denys.cn/v1/query?ip=223.5.5.5", nil)
	req.Header.Set("X-API-Key", "ipk_your_key")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	var data map[string]any
	json.NewDecoder(resp.Body).Decode(&data)
	fmt.Println(data)
}
```

**Rust**

```
use reqwest::blocking::Client;

fn main() -> Result<(), Box<dyn std::error::Error>> {
	let text = Client::new()
		.get("https://api.ip.denys.cn/v1/query?ip=223.5.5.5")
		.header("X-API-Key", "ipk_your_key")
		.send()?
		.text()?;
	println!("{text}");
	Ok(())
}
```

## MCP（AI Agent 接入）

本服务提供无状态 MCP 远程端点（Streamable HTTP）：`POST https://api.ip.denys.cn/mcp`，JSON-RPC 2.0。
鉴权与 REST 相同（X-API-Key 或 Authorization: Bearer 头），工具调用按次计费、仅命中计费。

工具：

| 名称 | 参数 | 说明 |
|---|---|---|
| ip_query | { ip?: string } | 查询单个 IP（IPv4/IPv6）；省略 ip 时查调用方出口 IP |
| ip_batch | { ips: string[] } | 批量查询，最多 100 个，按命中计费 |
| ip_quota | {} | 查询当前 Key 剩余次数（不计费） |

字段说明（与 REST 接口完全一致，见上文「返回格式」的完整字段表）：
- `country`/`province`/`city`/`isp`/`country_code`：基础归属地字段
- `is_china_mainland`：是否中国大陆（港澳台为 false）
- `region`：地区归类 mainland/hk/mo/tw/overseas；**`china_region` 是国内大区（华东/华北/华南/华中/西南/西北/东北，港澳台不返回）——两者含义不同，勿混用**
- `phone_prefix` 国际电话区号（大陆 +86 / 香港 +852 / 澳门 +853 / 台湾 +886）；`city_area_code` 城市区号
- `china_province_code`/`china_city_code` 行政区划代码；`city_code`/`city_short_code` 城市拼音与简码
- `asn`/`as_org`：自治系统号与所属网络

注意：信息不可用时对应字段不返回（如海外 IP 常无 `city_code`、港澳台无城市字段），属正常情况，不应视为错误重试。

Claude Code 等 CLI 工具接入：`claude mcp add --transport http ip-geo https://api.ip.denys.cn/mcp --header "X-API-Key: ipk_xxx"`；
Claude Desktop / Cursor 等客户端在 mcpServers 配置 { "url": "https://api.ip.denys.cn/mcp", "headers": { "X-API-Key": "ipk_xxx" } }。

## 常见问题

### 多少钱一次？

套餐单价低至 0.0004 元/次（1 元最多可查 2,500 次）：入门 ¥5/5,000 次约 0.001 元/次，旗舰 ¥100/250,000 次为 0.0004 元/次。在同类 IP 查询 API 中属于便宜档，且仅查询命中计费，未命中与出错都不扣次数。

### 和免费接口、大厂云 API 相比有什么优势？

免费 IP 查询接口通常限流严格、数据更新和稳定性没有保障，随时可能停服或转向收费；大厂云 API 功能全但按量计费单价高。我们只做 IP 归属地查询这一件事，所以能做得更便宜：1 元最多可查 2,500 次，且仅查询命中才计费。

### 注册后有免费额度吗？

有。注册并完成邮箱验证后自动赠送 1,000 次查询额度，可以先验证数据质量再决定是否付费。

### 哪些查询会计费？

只在查询成功且有结果（found=true）时计 1 次。IP 格式非法、未收录地址（如内网地址）以及查询失败都不计费；每次成功响应的 X-Quota-Remaining 头会实时返回剩余次数。

### 次数用完会怎样？会自动扣费吗？

不会自动扣费。次数用尽后接口返回 402，充值后立即可用；所有次数长期有效，不设过期时间。

### 支持查询哪些信息？包含 IPv6 吗？

支持 IPv4 与 IPv6，毫秒级返回国家、省份、城市、运营商，共 20+ 个字段：还包含是否中国大陆（is_china_mainland）、地区归类、大洲、国际电话区号（港澳台各自独立）、省/市行政区划码、省份拼音/简码/简称、国内大区、城市拼音/简码/电话区号，以及 ASN（自治系统号）与所属组织；另有批量接口，一次最多查询 100 个 IP，按命中条数计费。

### 港澳台 IP 的查询结果怎么显示？

香港、澳门、台湾统一返回 country=中国、country_code=CN，以 province 区分：香港特别行政区、澳门特别行政区、台湾省。同时提供 is_china_mainland（是否中国大陆）与 region（mainland/hk/mo/tw/overseas）字段，判断无需自己维护名单；电话区号也按地区区分（大陆 +86、香港 +852、澳门 +853、台湾 +886）。

### AI 助手或编程 Agent 能直接接入吗？

可以。本站提供 MCP 远程端点（https://api.ip.denys.cn/mcp）与 AI 可读的完整接口说明（https://api.ip.denys.cn/llms-full.txt）：在 Claude Code / Cursor 等工具里加一行 MCP 配置即可调用；Agent 调用与人工调用同规则计费（按次、仅命中计费），注册赠送的 1,000 次足够完成试用与调试。

### 有调用频率限制吗？

有，默认每个 API Key 约 50 次/秒，超出返回 429，按业务并发量正常轮询不会触发；大批量场景建议改用批量接口合并请求。

### API Key 泄露了怎么办？

在控制台可随时重置或禁用：重置后旧 Key 立即失效。每个账号最多可创建 50 个 Key，建议按开发/生产等环境分开管理。
