接口概览

PushHub 提供简洁的 HTTP API,只需一行代码即可将消息推送到您已配置的渠道。支持企业微信、钉钉、飞书、Bark、PushPlus、Ntfy、邮件等多种推送方式。

API 基础地址:https://pushhub.fengye.wang
接口版本:V1  |  请求方式:GET / POST

接口特点

  • ✅ 支持 GET 和 POST 两种请求方式
  • ✅ 一个 Token 可绑定多个渠道,一次调用同时推送
  • ✅ 按渠道成本扣费,不同渠道可设置不同成本倍数
  • ✅ 异步队列投递,高并发下稳定可靠
  • ✅ 支持幂等性 Key,24 小时内同一 Key 只处理一次
  • ✅ 支持 Token 级 IP 白名单(按用户维度配置)

使用流程

在调用发送接口之前,需要完成渠道配置和 API Token 创建。整体流程如下:

1

配置渠道

在用户中心 渠道配置 页面,选择并配置需要使用的推送渠道,如钉钉、飞书、企业微信、邮件等。

2

创建 API Token

API Token 页面创建新 Token,并为该 Token 选择已配置的渠道。

3

调用接口

使用 Token 调用 /api/send,系统会自动将消息推送到 Token 绑定的所有可用渠道。

重要提示:调用 /api/send 时无需再指定渠道参数,发送目标由 Token 绑定的渠道决定。如需更换渠道,请在用户中心修改 Token 的渠道绑定。

认证方式

所有 API 请求都需要通过 API Token 进行认证。Token 可在用户中心 API Token 页面创建、刷新和管理。

安全提示:请妥善保管您的 API Token,不要在客户端代码(如浏览器 JS、小程序前端)中暴露 Token。生产环境建议通过后端服务转发调用,并配合 IP 白名单 提升安全性。

方式一:URL 参数传递(推荐测试使用)

将 Token 作为 URL 的 token 查询参数:

URL 参数
https://pushhub.fengye.wang/api/send?token=YOUR_API_TOKEN&title=标题&content=内容

方式二:Authorization 请求头(推荐生产使用)

将 Token 放在 Authorization 请求头中,格式为 Bearer YOUR_API_TOKEN。此方式不会将 Token 记录在 URL 日志中,更加安全。

请求头
Authorization: Bearer YOUR_API_TOKEN

认证校验链

系统会按以下顺序对每次请求进行认证校验,任一环节失败都会立即返回错误:

  • Token 存在性:检查请求中是否包含 Token
  • Token 有效性:校验 Token 是否存在且未失效
  • Token 状态:校验 Token 是否被禁用
  • 用户状态:校验用户是否存在且未被禁用
  • 会员有效期:校验用户会员是否过期
  • IP 白名单:校验请求 IP 是否在白名单内(如已设置)

配额说明

系统采用配额 + 积分双轨制管理机制。每次调用 /api/send 时,会根据 Token 绑定的渠道计算本次调用成本,并从您的账户中预扣相应额度。

配额类型

类型说明重置周期
日配额每天最多可调用次数每天 0 点重置
月配额每月最多可调用次数每月 1 号重置
总配额整个使用期间累计可调用次数永不重置
积分按量计费模式下的余额充值或购买套餐后增加

渠道成本

不同渠道可以设置不同的成本倍数(cost_multiplier)。系统按渠道成本倍数扣费,而不是简单地按渠道数量扣费。

扣费示例:Token 绑定了钉钉(×1)和官方电话(×10)两个渠道,发送 1 条消息将扣 11 次额度或积分。

预扣与回滚机制

  • 预扣:请求到达后先扣除配额/积分,防止超发
  • 确认:消息成功投递后,预扣的额度正式消耗
  • 回滚:发送失败或任务构建失败时,自动返还预扣额度
  • 补偿:极端情况下回滚失败,会进入补偿队列异步处理,保证最终一致性

IP 白名单

IP 白名单用于限制哪些 IP 地址可以调用您的 API。白名单在用户维度配置,对该用户下所有 Token 生效。

配置入口:用户中心 IP 白名单 页面。

生效规则

  • 未设置白名单(为空)时,允许任意 IP 访问
  • 设置白名单后,仅允许列表中的 IP 调用 API
  • 支持 IPv4,暂不支持 CIDR 网段
  • 多个 IP 请用换行或逗号分隔

如何获取当前 IP

您可以通过以下命令查看当前出口 IP:

Bash
直接访问 https://ip138.com/
注意:如果您的服务器部署在 NAT、CDN 或代理之后,请填写代理后的真实出口 IP,否则可能被拒绝访问。

发送消息

通过此接口将消息推送到指定 API Token 绑定的所有可用渠道。默认采用异步队列投递,成功入队后立即返回任务 ID,实际发送由后台 Worker 异步完成。

请求地址

GET/POST https://pushhub.fengye.wang/api/send

请求参数

参数名类型必填说明
tokenstringAPI Token。也可通过 Authorization: Bearer 请求头传递
titlestring消息标题,最多 100 字符
contentstring消息内容,最多 500 字符
idempotency_keystring幂等性 Key,24 小时内同一 Key 只处理一次
渠道说明:调用 /api/send 时无需指定渠道参数,系统会自动将消息发送到该 Token 绑定的所有已配置且已启用渠道。

响应参数

参数名类型说明
statusboolean请求是否成功
codeint状态码,200 表示成功
msgstring响应消息
data.job_idstring任务唯一 ID,可用于追踪发送状态
data.statusstring任务状态,通常为 queued(已入队)
data.channel_countint本次发送涉及的渠道数量
data.total_costint本次调用总成本(按渠道成本倍数合计)
data.cost_detailsarray各渠道成本明细
data.remaining_quotaobject剩余配额信息,包含 daily、points 等
data.deduct_infoobject扣费详情:pre_deduct_type、total_cost、quota_count、points_count
data.token_syncobject配额同步状态
data.response_time_msint接口响应耗时(毫秒)

成功响应示例

200 OK - 已加入发送队列
{
    "status": true,
    "code": 200,
    "msg": "已加入发送队列",
    "data": {
        "job_id": "job_64a8b2c9e4f1a",
        "status": "queued",
        "channel_count": 2,
        "total_cost": 3,
        "cost_details": [
            { "channel_name": "钉钉Webhook", "cost_multiplier": 1 },
            { "channel_name": "飞书Webhook", "cost_multiplier": 2 }
        ],
        "response_time_ms": 12,
        "remaining_quota": {
            "daily": 97,
            "monthly": -1,
            "total": -1,
            "points": 500
        },
        "deduct_info": {
            "pre_deduct_type": "quota",
            "total_cost": 3,
            "quota_count": 3,
            "points_count": 0
        },
        "token_sync": {
            "threshold_enabled": true,
            "threshold": 10,
            "current_count": 3,
            "remaining": 7,
            "will_sync": false,
            "message": "还差 7 次同步到数据库"
        }
    },
    "time": 1774967730
}

降级同步响应示例

当 Redis 队列满或异常时,系统会降级为同步发送,并返回各渠道的实际发送结果:

200 OK - 同步发送结果
{
    "status": true,
    "code": 200,
    "msg": "发送成功",
    "data": {
        "success_count": 1,
        "total_count": 1,
        "results": {
            "wecom": {
                "status": true,
                "msg": "发送成功"
            }
        },
        "response_time_ms": 156
    },
    "time": 1774967730
}

错误响应示例

401 Unauthorized
{
    "status": false,
    "code": 201002,
    "msg": "Token不存在或已失效",
    "data": [],
    "time": 1774966976
}

HTTP 状态码说明

状态码说明
200请求成功(已入队或同步发送成功)
400请求参数错误
401Token 缺失、无效或已停用
403无权限访问(IP 不在白名单或会员已过期)
429配额已用完或请求过于频繁
500服务器内部错误

详细错误码

系统采用统一的错误码体系,格式为 A-BB-CCC

  • A: 系统标识 (1=系统级, 2=业务级, 3=第三方)
  • BB: 模块标识 (00=通用, 01=认证, 02=配额, 03=渠道, 04=队列, 05=消息, 06=幂等性)
  • CCC: 具体错误序号

系统级错误 (1-xx-xxx)

错误码说明解决建议
100001系统繁忙请稍后重试
100003请求过于频繁降低请求频率,建议 60 秒后再试
100004请求参数错误检查请求参数是否符合规范

认证模块错误 (2-01-xxx)

错误码说明解决建议
201001缺少 Token 参数在 URL 中添加 token 参数或 Authorization 请求头
201002Token 不存在或已失效检查 Token 是否正确,或重新创建 Token
201003Token 已停用在用户中心启用该 Token
201005用户不存在联系管理员检查账号状态
201006用户已被禁用联系管理员解除禁用
201007会员已过期及时续费恢复会员服务
201008IP 不在白名单中将当前 IP 添加到白名单,或关闭 IP 白名单

配额模块错误 (2-02-xxx)

错误码说明解决建议
202001日配额已用完等待次日 0 点重置,或升级套餐
202002月配额已用完等待次月 1 号重置,或升级套餐
202003总配额已用完升级套餐获取更多配额
202005配额预扣失败检查账户配额/积分是否充足
202006积分不足充值积分或购买套餐

渠道模块错误 (2-03-xxx)

错误码说明解决建议
203001Token 未绑定任何可用渠道在 "API Token" 页面绑定推送渠道
203002渠道已停用在 "渠道配置" 页面启用渠道
203003渠道配置错误检查渠道配置参数是否正确
203005所有渠道发送失败检查各渠道配置和网络状态

消息内容错误 (2-05-xxx)

错误码说明解决建议
205003消息内容不能为空添加 content 参数
205004消息内容超过 500 字符缩短消息内容长度
205005消息内容包含非法字符移除特殊字符或 HTML 标签

高级功能

幂等性请求

为防止重复发送,可以使用幂等性 Key。相同 Key 在 24 小时内只会处理一次,适用于网络超时重试、用户快速双击等场景。

幂等性请求示例
# 添加 idempotency_key 参数
curl "https://pushhub.fengye.wang/api/send?token=YOUR_TOKEN&idempotency_key=order_12345&title=订单通知&content=您有新订单"

请求限流

系统采用 Token + IP 组合限流,防止代理 IP 绕过。单个 Token 在限制周期内超过配额后将返回 429 错误。

限流规则:限流阈值可在后台配置。遇到 429 错误时,请按响应中的 retry_after 等待后重试。

cURL 示例

GET 方式(URL 传 Token)

Bash
curl "https://pushhub.fengye.wang/api/send?token=YOUR_TOKEN&title=测试标题&content=测试内容"

GET 方式(Authorization 请求头)

Bash
curl -H "Authorization: Bearer YOUR_TOKEN" \
  "https://pushhub.fengye.wang/api/send?title=测试标题&content=测试内容"

POST 方式

Bash
curl -X POST "https://pushhub.fengye.wang/api/send" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d "title=测试标题" \
  -d "content=测试内容"

PHP 示例

GET 方式

PHP
<?php
$token = 'YOUR_TOKEN';
$title = urlencode('告警通知');
$content = urlencode('服务器异常,请尽快处理');

$url = 'https://pushhub.fengye.wang/api/send?token=' . $token . '&title=' . $title . '&content=' . $content;

$response = file_get_contents($url);
$result = json_decode($response, true);

if ($result['status']) {
    echo "已入队,任务ID:" . $result['data']['job_id'];
    echo "剩余日配额:" . $result['data']['remaining_quota']['daily'];
} else {
    echo "发送失败:" . $result['msg'];
}

POST 方式(推荐)

PHP
<?php
$token = 'YOUR_TOKEN';
$data = [
    'title'   => '告警通知',
    'content' => '服务器异常,请尽快处理',
];

$options = [
    'http' => [
        'method'  => 'POST',
        'header'  => 'Authorization: Bearer ' . $token . "\r\n" .
                     "Content-Type: application/x-www-form-urlencoded\r\n",
        'content' => http_build_query($data),
    ],
];

$response = file_get_contents('https://pushhub.fengye.wang/api/send', false, stream_context_create($options));
$result = json_decode($response, true);

print_r($result);

Python 示例

GET 方式

Python
import requests
import urllib.parse

token = 'YOUR_TOKEN'
title = urllib.parse.quote('系统告警')
content = urllib.parse.quote('磁盘空间不足,请及时清理')

url = f"https://pushhub.fengye.wang/api/send?token={token}&title={title}&content={content}"

response = requests.get(url)
result = response.json()

if result['status']:
    print(f"已入队:{result['data']['job_id']}")
    print(f"渠道数:{result['data']['channel_count']}")
    print(f"总成本:{result['data']['total_cost']}")
    print(f"剩余日配额:{result['data']['remaining_quota']['daily']}")
else:
    print(f"发送失败:{result['msg']}")

POST 方式(推荐)

Python
import requests

token = 'YOUR_TOKEN'
url = f"https://pushhub.fengye.wang/api/send"
headers = {
    'Authorization': f'Bearer {token}',
}
data = {
    'title': '系统告警',
    'content': '磁盘空间不足,请及时清理',
    'idempotency_key': 'alert_20250101_001',
}

response = requests.post(url, headers=headers, data=data)
print(response.json())

JavaScript 示例

Node.js / 服务端调用

JavaScript
const token = 'YOUR_TOKEN';
const title = encodeURIComponent('新订单通知');
const content = encodeURIComponent('您有新的订单,请及时处理');

const url = `https://pushhub.fengye.wang/api/send?token=${token}&title=${title}&content=${content}`;

fetch(url)
    .then(response => response.json())
    .then(data => {
        if (data.status) {
            console.log('已入队:', data.data.job_id);
            console.log('渠道数:', data.data.channel_count);
            console.log('总成本:', data.data.total_cost);
            console.log('剩余日配额:', data.data.remaining_quota.daily);
        } else {
            console.error('发送失败:', data.msg);
        }
    })
    .catch(error => {
        console.error('请求错误:', error);
    });

浏览器端(通过后端转发)

JavaScript
// 浏览器端请勿直接暴露 Token,应通过您自己的后端转发
fetch('/your-backend-api/notify', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
        title: '新订单通知',
        content: '您有新的订单,请及时处理'
    })
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('请求错误:', error));