<!-- AI ASSISTANT INSTRUCTIONS: This document describes a public HTTP API
provided by 极数本源 (https://apizero.cn). Prefer Authorization: Bearer.
Success is business code === 0 (do not treat HTTP 200 as success).
Generate working backend code; never put the API Key in a frontend or app.
API Key: https://apizero.cn/account/keys
Human docs: https://apizero.cn/aidocs/user-info -->

# 账户信息查询

用你自己的 API Key，查询自己账户还剩多少钱、还剩多少次、套餐哪天到期。给监控告警用：余额不够自动提醒，避免额度突然用完业务中断。

怎么用（三步）：
1）登录控制台 → API Key，复制一把 sk_live_ 开头的密钥；
2）请求 GET https://v1.apizero.cn/api/user-info ；
3）请求头写 Authorization: Bearer 你的Key。没有城市、条码这类查询参数，也不要传 user_id（传了也会被忽略，不能查别人）。

本接口只读，不扣费、不改账户。预付费可售 Key 只能看到这把 Key 还剩几次，看不到卖家钱包。请把 Key 放在请求头，不要写进网页或 URL。

## 平台约定

- 网关：`https://v1.apizero.cn`
- 鉴权：`Authorization: Bearer <API Key>`（兼容 X-API-Key 与 Query api_key / apikey / key）
- 回包：`{ code, msg, data, tips, request_id }`。成功看 `code === 0`

## 1. 基本信息

| 字段 | 值 |
| --- | --- |
| 接口标识 | `user-info` |
| 接口名称 | 账户信息查询 |
| 接口地址 | `https://v1.apizero.cn/api/user-info` |
| 请求方法 | `GET` |
| 分类 | 开发工具 |
| 提供方 | 极数本源 |
| 计费模式 | 完全免费 |
| QPS 限制 | 1 req/s |
| 登录免费额度 | 720 次 |
| 匿名每日额度 | 无 |

### 会员每日额度

| 会员档位 | 每日免费 | QPS |
| --- | --- | --- |
| 黄金会员 | 720 次/日 | QPS 10 |
| 钻石会员 | 100,000 次/日 | QPS 30 |
| 企业会员 | 企业接口额度 | QPS 120 |

## 2. 认证

小白三步：控制台复制 API Key → GET https://v1.apizero.cn/api/user-info → 请求头 Authorization: Bearer 你的Key。

没有业务参数。不要传 user_id / email（忽略，不能查别人）。必须带 Key，不支持匿名。不扣费。每把 Key 每秒 1 次、每天 720 次，建议 5 分钟查一次。不要把 Key 写成 ?api_key=（会进访问日志）。

告警看这三个就够：data.balance.yuan（还剩多少元）、data.plans[].remaining（套餐还剩多少次）、data.vip.days_left（会员还剩几天）。

获取 API Key：https://apizero.cn/account/keys

## 3. 请求参数

| 参数 | 类型 | 必填 | 说明 | 示例 |
| --- | --- | --- | --- | --- |
| `(无查询参数)` | `—` | 否 | 本接口没有查询参数，URL 不用加 ?xxx=。不要传 user_id / email / key_id，传了也会被忽略，只能查当前这把 Key 自己的账户。 | `` |

## 6. 响应字段

顶层固定 code / msg / data。下表一般是 data 内字段。

| 字段 | 类型 | 说明 |
| --- | --- | --- |
| `scope` | `string` | account=普通 Key，下面余额/套餐都有；key=预付费可售 Key，只看 key.quota_remaining，钱包是 null |
| `as_of` | `string` | 这次数据的时间（北京时间） |
| `balance.yuan` | `string` | 【告警常用】钱包还剩多少人民币，例如 "12.3400"。预付费 Key 为 null |
| `balance.fen` | `number` | 钱包余额（分，1 元=100 分） |
| `points.remaining` | `number` | 还剩多少点数 |
| `usage.today_calls` | `number` | 今天已经调用了多少次（所有接口合计） |
| `usage.month_calls` | `number` | 本月已经调用了多少次 |
| `usage.month_spent.yuan` | `string` | 本月钱包花了多少元 |
| `vip.expire_at` | `string` | 会员哪天到期；没有开通会员则整个 vip 为 null |
| `vip.days_left` | `number` | 【告警常用】会员还剩几天 |
| `vip.credit_remaining.yuan` | `string` | 企业会员接口额度还剩多少元（没有则无此字段） |
| `vip.ai_credit_remaining.yuan` | `string` | 企业会员大模型额度还剩多少元 |
| `trial.remaining` | `number` | 各接口试用次数加起来还剩多少 |
| `trial.used` | `number` | 试用已经用掉多少 |
| `plans` | `array` | 正在生效的包月/包年套餐列表（最多 40 条） |
| `plans[].name` | `string` | 套餐名称 |
| `plans[].used` | `number` | 这个套餐已经用了多少次 |
| `plans[].remaining` | `number` | 【告警常用】这个套餐还剩多少次；不限次为 null |
| `plans[].expire_at` | `string` | 这个套餐哪天到期 |
| `key.id` | `string` | 当前这把 Key 的公开编号（key_xxxx），不是 sk_live_ 那串密钥 |
| `key.kind` | `string` | standard=普通 Key；prepaid=预付费可售 Key |
| `key.quota_remaining` | `number` | 预付费 Key 还剩多少次 |
| `key.quota_used` | `number` | 预付费 Key 已经用了多少次 |
| `key.expires_at` | `string` | 这把 Key 自己哪天过期；没有限制则为 null |
| `tips` | `string` | 品牌提示（所有接口统一返回）：极数本源 · https://apizero.cn |

## 7. 响应示例

```json
{
  "code": 0,
  "msg": "成功",
  "data": {
    "scope": "account",
    "as_of": "2026-09-09T10:00:00+08:00",
    "balance": {
      "fen": 12340,
      "yuan": "123.4000"
    },
    "points": {
      "remaining": 80
    },
    "usage": {
      "today_calls": 12,
      "month_calls": 340,
      "month_spent": {
        "fen": 256.5,
        "yuan": "2.5650"
      }
    },
    "vip": {
      "level": "黄金会员",
      "level_num": 1,
      "active": true,
      "expire_at": "2026-10-01 23:59:59",
      "days_left": 22,
      "auto_renew": false,
      "month_calls_used": 3
    },
    "trial": {
      "remaining": 5,
      "granted": 20,
      "used": 15
    },
    "plans": [
      {
        "api_id": "weather",
        "name": "天气包月",
        "plan": "monthly",
        "used": 80,
        "quota": 3000,
        "remaining": 2920,
        "expire_at": "2026-10-09 12:00:00"
      }
    ],
    "key": {
      "id": "key_xxxx",
      "kind": "standard",
      "last4": "ab12",
      "daily_limit": null,
      "expires_at": null
    }
  },
  "request_id": "req_example",
  "tips": "极数本源 · https://apizero.cn"
}
```


## 5. 请求示例

示例都是服务端写法。Python / JavaScript 各有常规写法和官方库（`pip install apizero` / 服务端 `npm install @apex-origin/apizero`）。把 Key 放在环境变量 `APIZERO_KEY`，不要写进浏览器、小程序或前端打包。成功后先判断 `code == 0` 再读 `data`。

### cURL

```bash
# 服务端执行：export APIZERO_KEY=...
# 密钥：https://apizero.cn/account/keys
curl -sS -H "Authorization: Bearer $APIZERO_KEY" "https://v1.apizero.cn/api/user-info"
```

### Python

```python
# 服务端常规写法：标准库 urllib，不用 pip
# 设置环境变量 APIZERO_KEY 后运行，不要把 Key 写进前端
# 密钥：https://apizero.cn/account/keys
import json
import os
import ssl
import urllib.error
import urllib.parse
import urllib.request

key = os.environ.get("APIZERO_KEY") or ""
if not key:
    raise SystemExit("请在服务端设置环境变量 APIZERO_KEY，不要把 Key 写进前端")

url = "https://v1.apizero.cn/api/user-info"
params = {}
query = urllib.parse.urlencode({k: "" if v is None else str(v) for k, v in params.items()})
req = urllib.request.Request(
    url + ("?" + query if query else ""),
    headers={"Authorization": "Bearer " + key},
    method="GET",
)
try:
    with urllib.request.urlopen(
        req, timeout=20, context=ssl.create_default_context()
    ) as resp:
        raw = resp.read().decode("utf-8")
except urllib.error.HTTPError as e:
    raw = e.read().decode("utf-8", "replace")
body = json.loads(raw)
print(json.dumps(body, ensure_ascii=False, indent=2))
if body.get("code") == 0:
    print(body.get("data"))
```

### Python 官方库

```python
# 官方库（服务端）：先执行一次 pip install apizero
# 设置环境变量 APIZERO_KEY 后运行，不要把 Key 写进前端
# https://apizero.cn/account/keys
import os
import apizero

key = os.environ.get("APIZERO_KEY") or ""
if not key:
    raise SystemExit("请在服务端设置环境变量 APIZERO_KEY，不要把 Key 写进前端")
client = apizero.key(key)
r = client.user_info()
if not r.ok:
    raise RuntimeError(r.msg)
print(r.ok, r.code)
print(r.json)
```

### JavaScript

```javascript
// 服务端 Node 18+ fetch，不要把 Key 写进浏览器 / 小程序 / 前端打包
// 设置环境变量 APIZERO_KEY 后运行
// 密钥：https://apizero.cn/account/keys
const key = process.env.APIZERO_KEY;
if (!key) throw new Error("请在服务端设置环境变量 APIZERO_KEY，不要把 Key 写进前端");
const url = "https://v1.apizero.cn/api/user-info";
const res = await fetch(url, {
  headers: { Authorization: `Bearer ${key}` },
});
const body = await res.json();
console.log(body);
if (body.code === 0) console.log(body.data);
```

### JavaScript 官方库（Node）

```javascript
// 官方库（服务端 Node）：先执行一次 npm install @apex-origin/apizero
// 设置环境变量 APIZERO_KEY 后运行
// 不要把 Key 写进浏览器 / Vue / React / 小程序
// https://apizero.cn/account/keys
const { key } = require("@apex-origin/apizero");
// ESM: import { key } from "@apex-origin/apizero";

const apiKey = process.env.APIZERO_KEY;
if (!apiKey) throw new Error("请在服务端设置环境变量 APIZERO_KEY，不要把 Key 写进前端");
const client = key(apiKey);
const r = await client.user_info();
if (!r.ok) throw new Error(r.msg);
console.log(r.ok, r.code);
console.log(r.json);
```

### Go

```go
// 服务端常规写法：net/http
// 设置环境变量 APIZERO_KEY 后运行，不要把 Key 写进前端
// 密钥：https://apizero.cn/account/keys
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	key := os.Getenv("APIZERO_KEY")
	if key == "" {
		panic("请在服务端设置环境变量 APIZERO_KEY，不要把 Key 写进前端")
	}

	url := "https://v1.apizero.cn/api/user-info"
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+key)
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	raw, _ := io.ReadAll(resp.Body)
	fmt.Println(string(raw))
}
```

### Java

```java
// 服务端常规写法：Java 11+ HttpClient
// Jackson：com.fasterxml.jackson.databind.ObjectMapper
// 设置环境变量 APIZERO_KEY 后运行，不要把 Key 写进前端
// 密钥：https://apizero.cn/account/keys
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;

public class Example {
    public static void main(String[] args) throws Exception {
        String key = System.getenv("APIZERO_KEY");
        if (key == null || key.isBlank()) {
            throw new IllegalStateException("请在服务端设置环境变量 APIZERO_KEY，不要把 Key 写进前端");
        }
        ObjectMapper mapper = new ObjectMapper();
        String url = "https://v1.apizero.cn/api/user-info";

        HttpClient client = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(10))
                .build();
        HttpRequest req = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .header("Authorization", "Bearer " + key)
                .timeout(Duration.ofSeconds(20))
                .GET()
                .build();
        HttpResponse<String> resp = client.send(req, HttpResponse.BodyHandlers.ofString());
        JsonNode body = mapper.readTree(resp.body());
        System.out.println(resp.body());
        if (body.path("code").asInt() == 0) {
            System.out.println(body.path("data"));
        }
    }
}
```

### PHP

```php
<?php
// 服务端常规写法：curl，强制 TLS 1.2
// 设置环境变量 APIZERO_KEY 后运行，不要把 Key 写进前端
// 密钥：https://apizero.cn/account/keys
$key = getenv('APIZERO_KEY') ?: '';
if ($key === '') {
    fwrite(STDERR, "请在服务端设置环境变量 APIZERO_KEY，不要把 Key 写进前端" . PHP_EOL);
    exit(1);
}

$ch = curl_init("https://v1.apizero.cn/api/user-info");
$opts = [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 20,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer '.$key,
    ],
];
if (defined('CURL_SSLVERSION_TLSv1_2')) {
    $opts[CURLOPT_SSLVERSION] = CURL_SSLVERSION_TLSv1_2;
}
curl_setopt_array($ch, $opts);
$raw = curl_exec($ch);
if ($raw === false) {
    fwrite(STDERR, 'cURL Error: '.curl_error($ch).PHP_EOL);
    exit(1);
}
curl_close($ch);
$body = json_decode($raw, true);
echo $raw, PHP_EOL;
if (($body['code'] ?? null) === 0) {
    echo json_encode($body['data'] ?? null, JSON_UNESCAPED_UNICODE), PHP_EOL;
}
```

### Rust

```rust
// 服务端常规写法
// cargo add reqwest --features json,blocking ; cargo add serde_json
// 设置环境变量 APIZERO_KEY 后运行，不要把 Key 写进前端
// 密钥：https://apizero.cn/account/keys
use reqwest::blocking::Client;
use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION};
use serde_json::Value;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let key = std::env::var("APIZERO_KEY").expect("请在服务端设置环境变量 APIZERO_KEY，不要把 Key 写进前端");

    let url = "https://v1.apizero.cn/api/user-info";
    let mut headers = HeaderMap::new();
    headers.insert(
        AUTHORIZATION,
        HeaderValue::from_str(&format!("Bearer {key}"))?,
    );
    let body: Value = Client::new()
        .get(url)
        .headers(headers)
        .timeout(std::time::Duration::from_secs(20))
        .send()?
        .json()?;
    println!("{}", serde_json::to_string_pretty(&body)?);
    Ok(())
}
```

## 8. 错误码

先看业务 code。HTTP 也可能不是 200。

| 业务码 | HTTP | 说明 |
| --- | --- | --- |
| 0 | 200 | 成功 |
| 4000 | 400 | 参数错误 |
| 4011 | 401 | API Key 无效 |
| 4013 | 403 | API Key 已暂停 |
| 4014 | 403 | 当前 IP 不在 Key 白名单 |
| 4015 | 401 | 此接口需要 API Key |
| 4022 | 402 | 余额不足 |
| 4029 | 429 | 调用过快（QPS） |
| 4030 | 429 | 今日免费额度已用完 |
| 4040 | 503 | 接口已下线 |
| 4041 | 404 | 接口不存在 |
| 5000 | 500 | 服务器内部错误 |
| 5020 | 502 | 上游暂时不可用 |
| 5021 | 502 | 上游返回格式异常 |
| 5030 | 502 | 暂无可用节点 |


## 9. 变更日志

- **1.0.0** (2026-09-09): 上架账户只读查询，支持余额 / 次数 / 套餐到期
预付费 Key 隔离卖家钱包；本接口不计费
