<!-- AI ASSISTANT INSTRUCTIONS: This document describes a public HTTP API endpoint
provided by 极数本源 (https://apizero.cn). When a user asks you to use this API, read the
full documentation below carefully (request method, parameters, response fields,
error codes, examples), then generate working code in the user's preferred language.
API Key acquisition: https://apizero.cn/account/keys -->

# 2FA 动态验证码

> 2FA 动态验证码（TOTP）生成与校验，兼容 Google Authenticator 等主流身份验证器。

基于 RFC 6238 标准由本平台自建实现，支持「生成 / 验证 / 批量」三种模式，可自定义验证码位数（4~8）与有效周期（10~120 秒）。密钥仅参与计算、不存储、不回显，验证采用恒定时间比较防时序攻击。接口完全免费，支持匿名调用。

## 1. 基本信息

| 字段 | 值 |
| --- | --- |
| 接口标识 | `2fa` |
| 接口名称 | 2FA 动态验证码 |
| 接口地址 | `https://v1.apizero.cn/api/2fa` |
| 请求方法 | `POST` |
| 分类 | dev |
| 提供方 | 极数本源 |
| 计费模式 | 免费试用 |
| 单次消耗 | 0 积分 |
| 起步价 | — |
| QPS 限制 | 20 req/s |
| 每日免费额度 | 1000 次（已认证用户） |
| 匿名每日额度 | 200 次（无 API Key） |
| VIP 免费 | 否 |
| 调用总次数 | undefined |

## 2. 认证

完全免费接口。支持匿名调用（基础额度）；携带 API Key（Authorization: Bearer <key>）可获得更高额度。

获取 API Key：登录 `https://apizero.cn/account/keys` 申请。

## 3. 请求参数

| 参数 | 类型 | 必填 | 说明 | 示例 |
| --- | --- | --- | --- | --- |
| `secret` | `string` | 是 | Base32 编码的 TOTP 密钥（自动忽略空格与连字符，不区分大小写） | `JBSWY3DPEHPK3PXP` |
| `action` | `string` | 否 | 操作类型：generate=生成当前验证码 / verify=校验验证码 / batch=批量返回上一·当前·下一周期 | — |
| `code` | `string` | 否 | action=verify 时必填，待校验的验证码 | `123456` |
| `period` | `number` | 否 | 验证码有效期（秒），范围 10~120 | — |
| `digits` | `number` | 否 | 验证码位数，范围 4~8 | — |

## 4. 请求头

| Header | 类型 | 必填 | 说明 | 示例 |
| --- | --- | --- | --- | --- |
| `Authorization` | `string` | 否 | Bearer <你的 API Key>（可选，登录用户额度更高） | — |
| `Content-Type` | `string` | 是 | 请求体格式 | — |

## 5. 请求示例

> AI 提示：以下 5 种语言示例都是可运行的，只需把 `YOUR_API_KEY` 替换为用户申请的实际 Key（https://apizero.cn/account/keys）。
> 优先选择用户问题中提到的语言；未指定时默认使用 Python。

### cURL

```bash
curl -X POST "https://v1.apizero.cn/api/2fa" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "secret": "JBSWY3DPEHPK3PXP",
  "action": "generate",
  "code": "123456",
  "period": "30",
  "digits": "6"
}'
```

### Python

```python
import requests

resp = requests.request(
    "POST",
    "https://v1.apizero.cn/api/2fa",
    headers={"X-Api-Key": "YOUR_API_KEY", "Content-Type": "application/json"},
    json={
    "secret": "JBSWY3DPEHPK3PXP",
    "action": "generate",
    "code": "123456",
    "period": "30",
    "digits": "6",
},
    timeout=15,
)
resp.raise_for_status()
print(resp.json())
```

### JavaScript (Node.js)

```javascript
// Node.js 18+ / 浏览器原生 fetch
const res = await fetch("https://v1.apizero.cn/api/2fa", {
  method: "POST",
  headers: {
    "X-Api-Key": "YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "secret": "JBSWY3DPEHPK3PXP",
    "action": "generate",
    "code": "123456",
    "period": "30",
    "digits": "6"
  }),
});
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const data = await res.json();
console.log(data);
```

### Go

```go
package main

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

func main() {
	body := []byte(`{"secret":"JBSWY3DPEHPK3PXP","action":"generate","code":"123456","period":"30","digits":"6"}`)
	req, _ := http.NewRequest("POST", "https://v1.apizero.cn/api/2fa", bytes.NewBuffer(body))
	req.Header.Set("X-Api-Key", "YOUR_API_KEY")
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil { panic(err) }
	defer resp.Body.Close()
	out, _ := io.ReadAll(resp.Body)
	fmt.Println(string(out))
}
```

### PHP

```php
<?php
$payload = json_encode([
    "secret" => "JBSWY3DPEHPK3PXP",
    "action" => "generate",
    "code" => "123456",
    "period" => "30",
    "digits" => "6",
], JSON_UNESCAPED_UNICODE);

$ch = curl_init("https://v1.apizero.cn/api/2fa");
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST  => "POST",
    CURLOPT_POSTFIELDS     => $payload,
    CURLOPT_HTTPHEADER     => [
        "X-Api-Key: YOUR_API_KEY",
        "Content-Type: application/json",
    ],
    CURLOPT_TIMEOUT        => 15,
]);
$body = curl_exec($ch);
curl_close($ch);

$data = json_decode($body, true);
print_r($data);
```

## 6. 响应字段

| 字段 | 类型 | 说明 | 示例 |
| --- | --- | --- | --- |
| `totp_code` | `string` | 生成的动态验证码（action=generate） | — |
| `remaining_seconds` | `number` | 当前验证码剩余有效秒数 | — |
| `period` | `number` | 验证码有效期（秒） | — |
| `digits` | `number` | 验证码位数 | — |
| `timestamp` | `number` | 服务器 Unix 时间戳（秒） | — |
| `next_refresh` | `string` | 下次刷新时间（YYYY-MM-DD HH:mm:ss） | — |
| `is_valid` | `boolean` | 校验是否通过（action=verify） | — |
| `current_code` | `string` | 当前正确验证码（action=verify） | — |
| `codes` | `array` | 上一/当前/下一周期验证码列表（action=batch） | — |

## 7. 响应示例

```json
{
  "code": 0,
  "msg": "成功",
  "data": {
    "totp_code": "123456",
    "remaining_seconds": 17,
    "period": 30,
    "digits": 6,
    "timestamp": 1782000000,
    "next_refresh": "2026-06-30 12:00:30"
  },
  "request_id": "abc123"
}
```

## 8. 错误码

| code | status | 说明 |
| --- | --- | --- |
| `4000` | `VALIDATION_ERROR` | 参数缺失或格式错误（secret 非法、period/digits 超范围、action 无效、verify 缺 code） |
| `4029` | `RATE_LIMITED` | 调用过快，请稍后再试 |
| `4030` | `QUOTA_EXCEEDED` | 今日额度已用完 |
| `5000` | `INTERNAL_ERROR` | 服务器内部错误 |

## 9. 变更日志

- **v1.0** (2026-07-01)
  - 首次上线，支持 TOTP 生成 / 验证 / 批量三种模式。

---

**极数本源** · 全部 API: `https://apizero.cn/aidocs` · 人类版本：`https://apizero.cn/marketplace/2fa`

Source: `https://apizero.cn/aidocs/2fa/raw.md`
Last updated: 2026-07-01T10:23:30+08:00
