内容
# apicity
[](https://github.com/justintanner/apicity/actions)
[](LICENSE)
[](tsconfig.base.json)
[](package.json)
众多API的薄封装:AI图像和视频生成、所有主要社交媒体API等。
## 特性
- **一次性密码支付门禁 — 无绕过。** 付费端点(媒体生成等)仅在绑定到确切请求的、由人类或代码客户端生成的、单次使用的OTP有效时才触发。自主代理无法自我批准或增加您的账单。
[详情 ↓](#付费端点-otp-支付门禁)
- **预估费用。** 对于计费提供商(openai, anthropic, xai, kimicoding, fireworks, alibaba, kie, elevenlabs)的纯本地美元预估 — 无需密钥,无需网络。
- **代理的模式。** 每个POST端点都附带一个zod请求模式(`endpoint.schema`)— 主机和代理在本地捕获幻觉调用,而不是在API处;MCP服务器将其用作工具的输入模式。
提供商包可以在运行时携带Zod 3或Zod 4;兼容性策略在 [docs/zod-compatibility.md](docs/zod-compatibility.md) 中有记录。
- **MCP服务器。** 每个端点都以1:1的比例公开为MCP工具。
- **可组合的中间件。** `withRetry` / `withFallback` / `withRateLimit` 作为普通的函数包装器。
- **最小的提供商依赖。** 提供商仅依赖于 `zod` — 除了`@apicity/polymarket`中的 `viem`用于订单签名。付费端点OTP验证和B2的S3兼容传输都捆绑在其提供商包中。ESM,严格的TypeScript。
## 示例
标题行为:**付费端点被门禁控制**。如果没有批准的、单次使用的OTP,调用将失败关闭 — 自主调用者无法绕过它。
```ts
import { createKie } from "@apicity/kie";
import { mintOtp, createCost } from "@apicity/cost";
// 代码客户端持有支付门禁的秘密(来自您的秘密管理器/配置)。自主调用者永远不会看到它,因此无法自我批准。
const secret = loadSecret();
const kie = createKie({
apiKey: process.env.KIE_API_KEY!,
paygate: { secret },
});
// 与POST到/api/v1/jobs/createTask相同的JSON正文。
const payload = {
model: "gpt-image-2-text-to-image",
input: {
prompt: "带有霓虹灯反射的电影般的夜间城市海报。",
aspect_ratio: "16:9",
resolution: "4K",
},
};
// 纯本地成本预览 — 无需密钥,无需网络,同步。
const estimate = createCost().estimate({ provider: "kie", payload });
// estimate.usd === 0.08
// 没有OTP → 失败关闭。 无绕过。
await kie.post.api.v1.jobs.createTask(payload);
// ❌ 抛出 PayGateError { code: "otp-missing" }
// 人类(或代码客户端)生成一个绑定到此请求的单次使用OTP。
const otp = mintOtp(secret, {
dotPath: "api.v1.jobs.createTask",
request: payload,
ttl: "10m",
});
// 已批准 — 运行一次。 重放OTP或更改任意字节的负载,验证失败。
const task = await kie.post.api.v1.jobs.createTask(payload, { otp });
```
直接KIE VEO调用与`createTask`分别控制:对于`kie.veo.post.api.v1.veo.generate`,使用`dotPath: "api.v1.veo.generate"`生成,对于`kie.veo.post.api.v1.veo.extend`,使用`dotPath: "api.v1.veo.extend"`。 上传、状态和帮助端点未列出,仍免费。
## 软件包
| 软件包 | 焦点 |
| ----------------------------------------------------------------- | ------------------------------------------------------------------ |
| [@apicity/openai](packages/provider/openai) | OpenAI聊天、回复、图像、音频、嵌入、文件 |
| [@apicity/anthropic](packages/provider/anthropic) | Anthropic消息、流、批次、文件、模型、管理API |
| [@apicity/xai](packages/provider/xai) | xAI聊天、回复、Grok图像/视频、文件、集合、搜索 |
| [@apicity/fal](packages/provider/fal) | fal模型注册、生成、定价、使用情况、分析 |
| [@apicity/google](packages/provider/google) | Google Gemini表达模式generateContent |
| [@apicity/kie](packages/provider/kie) | KIE媒体生成视频、图像、音频、Claude、Suno |
| [@apicity/alibaba](packages/provider/alibaba) | 阿里巴巴DashScope/Qwen聊天、图像和视频工作流程 |
| [@apicity/binance](packages/provider/binance) | Binance现货REST公共/常规端点 |
| [@apicity/openligadb](packages/provider/openligadb) | OpenLigaDB公共足球比赛数据、 standings和得分手 |
| [@apicity/fireworks](packages/provider/fireworks) | Fireworks聊天、嵌入、音频、部署、微调 |
| [@apicity/kimicoding](packages/provider/kimicoding) | Kimi Coding消息、流、模型、嵌入 |
| [@apicity/elevenlabs](packages/provider/elevenlabs) | ElevenLabs文本转语音、音效、音频API |
| [@apicity/s3](packages/provider/s3) | S3兼容对象存储 |
| [@apicity/b2](packages/provider/b2) | Backblaze B2 S3兼容对象存储 |
| [@apicity/free-media-upload](packages/provider/free-media-upload) | 公共文件上传/托管服务 |
| [@apicity/x](packages/provider/x) | X API发布和媒体上传 |
| [@apicity/meta](packages/provider/meta) | Instagram Graph API卷轴发布 |
| [@apicity/polymarket](packages/provider/polymarket) | Polymarket Gamma、数据和CLOB公共市场数据 |
| [@apicity/simplefunctions](packages/provider/simplefunctions) | SimpleFunctions公共预测市场和分析API |
| [@apicity/telegram](packages/provider/telegram) | Telegram Bot API文本、照片、视频和音频发送 |
| [@apicity/thesportsdb](packages/provider/thesportsdb) | TheSportsDB公共体育玩家数据 |
| [@apicity/cost](packages/provider/cost) | 跨提供商的纯本地成本/代币预估 |
| [@apicity/mcp-server](packages/mcp-server) | MCP服务器将提供商端点公开为工具 |
## MCP服务器
每个端点都是一个MCP工具。 使用包含提供商密钥的1Password保险箱或纯`.env`文件安装:
```bash
claude mcp add apicity -- \
npx -y @apicity/mcp-server@latest \
--op-vault apicity --op-token "$OP_SERVICE_ACCOUNT_TOKEN"
# 或
claude mcp add apicity -- \
npx -y @apicity/mcp-server@latest --env-file ~/.config/apicity/.env
```
Codex:与`codex mcp add apicity --`相同的命令。 详情见 [@apicity/mcp-server](packages/mcp-server)。
## 中间件
每个端点都是一个普通的`(req, signal?) => Promise<T>`函数,并且每个包都导出`withRetry`、`withFallback`和`withRateLimit` — 通用包装器可以组合,或者您可以将端点函数传递到您自己的编排层。(`@apicity/kimicoding`还提供`withStreamRetry` / `withStreamFallback`用于流异步迭代器。)
### `withRetry` — 指数级回退
对瞬时错误(HTTP 429和5xx)进行重试,带有可配置的回退:
```ts
import { createOpenAi, withRetry } from "@apicity/openai";
const openai = createOpenAi({ apiKey: process.env.OPENAI_API_KEY! });
const chat = withRetry(openai.v1.chat.completions, {
retries: 3, // 最大尝试次数(默认:2)
baseMs: 500, // 初始延迟(毫秒)(默认:300)
factor: 2, // 指数乘数(默认:2)
jitter: true, // 随机延迟±20%(默认:true)
});
```
### `withFallback` — 多提供商故障转移
按顺序尝试每个函数;包装器保持相同的签名,因此它们可以嵌套:
```ts
import { createXai, withFallback, withRetry } from "@apicity/xai";
const primary = createXai({ apiKey: process.env.XAI_API_KEY_PRIMARY! });
const backup = createXai({ apiKey: process.env.XAI_API_KEY_BACKUP! });
const image = withFallback([
withRetry(primary.v1.images.generations, { retries: 2 }),
withRetry(backup.v1.images.generations, { retries: 1 }),
]);
const result = await image({
model: "grok-2-image",
prompt: "一个小黄铜台灯的产品照片",
n: 1,
});
```
### `withRateLimit` — 客户端节流
通过共享限制器绑定每分钟请求数和并发数:
```ts
import {
createOpenAi,
withRateLimit,
createRateLimiter,
} from "@apicity/openai";
const openai = createOpenAi({ apiKey: process.env.OPENAI_API_KEY! });
const limiter = createRateLimiter({ rpm: 60, concurrent: 5 });
const chat = withRateLimit(openai.v1.chat.completions, limiter);
```
## 付费端点(OTP支付门禁)
具有直接边际成本的端点(例如`kie.post.api.v1.jobs.createTask`和`kie.veo.post.api.v1.veo.*`下的直接VEO调用)列在`PAID_ENDPOINTS`中,并被一个单次使用的OTP — 流程如上例所示 — 门禁控制。 门禁是**失败关闭**:付费调用需要提供商构造中的支付门禁秘密 **和** 从同一秘密生成的有效OTP。 自主调用者永远不会看到秘密,因此无法自我批准。 未列出的端点是免费的。
OTP使用单个共享的**HMAC秘密**签名 — 无需密钥文件,无需环境变量,无需成本耦合 — 并提交给确切的`(provider, method, dotPath, requestHash, exp)`元组:更改负载的任何字节,验证失败。 `jti`在调度前被消耗,因此失败的网络调用仍然会烧毁令牌 — 为任何重试请求一个新的OTP。
操作员(或代码客户端)使用`mintOtp(secret, { dotPath, request, ttl })`或CLI生成OTP — 从文件中读取秘密,而不是环境变量:
```bash
apicity-paygate otp mint \
--secret-file ./paygate.secret \
--dot-path api.v1.jobs.createTask \
--payload-file request.json \
--ttl 10m
```
被阻止的调用抛出`PayGateError`,其`.code`为`paygate-not-configured`、`otp-missing`、`otp-malformed`、`otp-invalid-signature`、`otp-expired`、`otp-mismatched-request`或`otp-replayed`。
门禁是通用的 — `xai`等其他提供商通过添加`PAID_ENDPOINTS`条目选择加入。 有关完整规范和MCP服务器的 `--paygate-secret-file`线路,请参见[@apicity/cost](packages/provider/cost)。
## 开发
- **运行时** — Node 18+,Cloudflare Workers,Deno,Bun。仅ESM。
- **构建和测试** — `pnpm install && pnpm run build && pnpm run test:run`。 集成测试通过Polly.js记录/重放(重放无需密钥)。
- **验证后发送** — 每个POST端点都公开一个`.schema`:`createOpenAi(...).v1.chat.completions.schema.safeParse(payload)`在API处捕获一个幻觉调用,而不是本地。
## 许可证
MIT — 见 [LICENSE](LICENSE).
基于[Nenad Bursac](https://github.com/nbursa/TetherAI)的[TetherAI](https://github.com/nbursa/TetherAI)。