API 文档
从取号到收码,一条清晰的接入路径。
查询账户与库存,创建号码订单,轮询短信并管理订单状态。
https://beansms.app创建订单前请确认余额充足。maxPrice 为最高接受单价,实际扣费不会超过该上限。
身份验证
账户及订单接口需要 Bearer 密钥;目录与报价无需密钥。网页登录 Cookie 不能代替 API Key。
Authorization: Bearer YOUR_API_KEY
API Key 为 64 位小写十六进制字符串。
密钥仅保存在服务端环境变量中,不要放入 URL、前端代码或日志。泄露后请联系管理员重置;旧密钥将立即失效。
请从服务端通过 HTTPS 调用。当前未开放跨域 CORS,不支持浏览器跨站直接调用。
以下请求示例使用服务端 Shell 和 cURL。将 BEANSMS_API_KEY 设置为自己的密钥,将 ORDER_ID 替换为创建响应的 order.id;SERVICE 示例为 kt。新建订单时更换 Idempotency-Key,重试原请求时保持不变。
账户信息
/api/v1/accountBearer返回当前密钥所属账户及余额,不返回邮箱、联系方式或密钥本身。无请求参数。
GET账户信息
curl --fail-with-body \
'https://beansms.app/api/v1/account' \
-H "Authorization: Bearer $BEANSMS_API_KEY"响应示例
{
"userId": 10000,
"label": "customer-reference",
"balance": {
"currency": "USD",
"amount": "10.01"
},
"scopes": ["account:read", "orders:read", "orders:write"]
}| 字段 | 类型 | 说明 |
|---|---|---|
userId | integer | 五位用户 ID |
label | string | 账户标签 |
balance | object | USD 余额,以十进制字符串返回,最多三位小数。 |
scopes | string[] | account:read, orders:read, orders:write |
服务与国家目录
/catalog.json公开使用 services[].code 查询报价,使用 countries[].code 匹配国家。
GET服务与国家目录
curl --fail-with-body 'https://beansms.app/catalog.json'响应结构节选
{
"services": [
{ "code": "kt", "name": "KakaoTalk",
"icon": "/catalog-icons/service-kt.svg" }
],
"countries": [
{ "code": "12",
"name": "United States (virtual)",
"nameZh": "美国(虚拟)", "iso": "UV", "prefix": "1",
"icon": "/catalog-icons/country-12.png" }
]
}代码按字符串处理,名称仅用于展示。目录存在某个服务或国家,不代表当前有库存。
库存与报价
/api/prices?service=kt公开service 为必填服务代码,必须来自目录且只能传入一次;不支持其他查询参数。响应可能包含多个币种。
GET库存与报价
SERVICE='kt'
curl --fail-with-body \
"https://beansms.app/api/prices?service=$SERVICE"响应示例
{
"service": "kt",
"priceType": "sale",
"currency": "USD",
"updatedAt": "2026-10-21T04:00:00.000Z",
"expiresAt": "2026-10-21T05:00:00.000Z",
"stale": false,
"syncFailed": false,
"rows": [
{ "country": "12", "currency": "USD",
"cost": "0.144", "stock": 20,
"tiers": [
{ "currency": "USD", "cost": "0.144",
"stock": 20, "stale": false },
{ "currency": "USD", "cost": "0.24",
"stock": 35, "stale": false }
]
}
]
}| 字段 | 类型 | 说明 |
|---|---|---|
priceType | string | sale:返回价格为可用于取号的售价。 |
currency | string | null | 统一币种;混合币种或无报价时为 null,以每档 currency 为准。 |
updatedAt / expiresAt | ISO 8601 | 报价更新时间与到期时间,均为 UTC。 |
stale / syncFailed | boolean | 任一值为 true 时建议刷新报价;库存不保证实时可用。 |
rows[].country | string | 目录中的国家代码 |
rows[].cost / stock | string / integer | 第一档的单价与库存,不是该国家的总库存。 |
rows[].tiers[] | object[] | 各价格档位及可用数量;总库存为所有档位 stock 之和。 |
cost 为十进制报价字符串。设置 maxPrice 时请使用 USD,并考虑实际费用保留三位小数;计算金额请使用十进制库。
rows 为空表示暂无该服务报价。报价不预留库存,取号结果以订单响应为准。
JavaScript · 服务端
const response = await fetch(
'https://beansms.app/api/prices?service=kt'
);
const data = await response.json();
if (!response.ok) throw new Error(data.error);
if (data.stale || data.syncFailed) {
throw new Error('Quote is not fresh');
}
for (const row of data.rows) {
const total = row.tiers.reduce(
(sum, tier) => sum + tier.stock, 0
);
console.log(row.country, total, row.tiers);
}Python · 服务端
import json
from urllib.request import urlopen
from decimal import Decimal
url = 'https://beansms.app/api/prices?service=kt'
# HTTP failures raise HTTPError.
with urlopen(url, timeout=15) as response:
data = json.load(response)
if data['stale'] or data['syncFailed']:
raise RuntimeError('Quote is not fresh')
for row in data['rows']:
for tier in row['tiers']:
price = Decimal(tier['cost'])
print(row['country'], price,
tier['currency'], tier['stock'])取号与短信
创建号码订单
/api/v1/ordersBearer每次新取号使用不同的 Idempotency-Key;网络重试必须沿用原键及相同参数,避免重复创建。键为 8–80 位字母、数字、下划线或连字符,按账户隔离。
POST限价取号
curl --fail-with-body \
'https://beansms.app/api/v1/orders' \
-H "Authorization: Bearer $BEANSMS_API_KEY" \
-H 'Content-Type: application/json' \
-H 'Idempotency-Key: order-live-0001' \
--data '{"service":"kt","country":"12","maxPrice":"0.150"}'| 字段 | 类型 | 说明 |
|---|---|---|
service | string | 必填,目录中的服务代码。 |
country | string | 必填,目录中的国家代码。 |
maxPrice | string | 可选,最高接受单价(USD),如 "0.150"。传入时须为大于零的十进制字符串,最多 10 位整数、9 位小数;省略 maxPrice 表示不限价。 |
限价取号
从不超过 maxPrice 的可用报价中优先选择最低价,按实际取号价格扣费,不按上限扣费。报价和三位小数扣费金额均不得超过上限,等于上限可以取号。无符合限价的报价返回 MAX_PRICE_EXCEEDED;取号无库存返回 NO_NUMBERS。
上述最低价优先适用于常规线路。特定线路可按限价向下匹配:从该服务、该国家当前有库存的公开售价档位中选择不超过 maxPrice 的最高一档;例如上限 0.50,有 0.48、0.45 档时按 0.48 报价和扣费,不生成不存在的 0.50 档。该报价是本单固定售价,不代表实际采购成本;不会超过客户上限。重试同一幂等键仍返回原订单及原报价。
例如 maxPrice="0.150",实际价格为 "0.144" 时扣费 0.144 USD;价格超过 0.150 USD 时不会取号。修改上限须使用新的幂等键;"0.15" 与 "0.150" 视为相同上限。
不限价取号仅传 service 和 country,例如 {"service":"kt","country":"12"}。所有可用 USD 档位均可参与选择,优先最低价,按实际选中档位扣费;不限价不代表免费,仍须余额充足。无可用档位返回 NO_NUMBERS。
需要限价时传 maxPrice。API 不接受 cost 参数,不提供精确价格取号。省略价格与传入价格属于不同请求,切换模式必须换新的幂等键。空字符串、null 和 0 均不表示不限价。请求体不接受其他字段及创建查询参数。
首次成功返回 201;同键同参数返回 200,参数不同返回 409。202 表示订单待确认,请查询原订单,不要换键重复创建。响应含 order 时检查 order.status 和 order.error;失败也可能返回 409 和 order。
响应示例
{
"order": {
"id": "num_00000000-0000-4000-8000-000000000001",
"service": "kt", "country": "12",
"serviceName": "KakaoTalk",
"serviceIcon": "/catalog-icons/service-kt.svg",
"status": "waiting",
"number": "+12025550100",
"price": { "currency": "USD", "amount": "0.144" },
"maxPrice": "0.15",
"refunded": false,
"createdAt": "2026-10-21T04:00:00.000Z",
"expiresAt": "2026-10-21T04:20:00.000Z",
"messages": [],
"error": null
}
}响应中的 price.amount 为本单扣费金额,maxPrice 为规范化上限,不限价订单为 null。number 是分配的号码;creating 或 review 状态下 number、expiresAt 可能为 null。示例值仅说明格式。
查询订单与短信
/api/v1/orders/{id}Bearer使用创建响应中的 order.id,每 10 秒查询一次。返回同一 order 对象;收到短信后 messages 包含以下内容,停止轮询并完成订单。
GET查询订单与短信
ORDER_ID='num_00000000-0000-4000-8000-000000000001'
curl --fail-with-body \
"https://beansms.app/api/v1/orders/$ORDER_ID" \
-H "Authorization: Bearer $BEANSMS_API_KEY"响应示例
// order.status = "received"
// order.messages:
[
{
"code": "123456",
"text": "123456"
}
]
完成与取消
/api/v1/orders/{id}/completeBearer/api/v1/orders/{id}/cancelBearer这两个操作均发送 JSON 空对象 {}。仅 received 可完成,仅 waiting 可取消;对同一终态重复操作返回 200,其他状态冲突返回 409。响应仍为完整 order 对象。
POST完成订单
ORDER_ID='num_00000000-0000-4000-8000-000000000001'
curl --fail-with-body \
"https://beansms.app/api/v1/orders/$ORDER_ID/complete" \
-H "Authorization: Bearer $BEANSMS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{}'POST取消订单
ORDER_ID='num_00000000-0000-4000-8000-000000000001'
curl --fail-with-body \
"https://beansms.app/api/v1/orders/$ORDER_ID/cancel" \
-H "Authorization: Bearer $BEANSMS_API_KEY" \
-H 'Content-Type: application/json' \
--data '{}'| status | 说明 |
|---|---|
creating | 取号处理中,查询原订单,不重复购买。 |
waiting | 等待短信,可申请取消;过早取消可能被拒绝。 |
received | 已收到短信,可完成,不可取消退款。 |
completed | 订单已完成,保留短信。 |
cancelled | 已确认取消,金额已退回账户余额。 |
failed | 取号明确失败,预扣金额已退回。 |
review | 订单待确认,请继续查询原订单,不要重复下单。 |
等待时限为 20 分钟,具体时间见 expiresAt。到期后请查询最终状态;仅 refunded=true 表示已退款。取消太早返回 CANCEL_TOO_EARLY,稍后重试原订单。
错误处理
HTTP 400
Content-Type: application/json
{"error":"INVALID_SERVICE"}
| HTTP | error | 说明 |
|---|---|---|
| 400 | INVALID_SERVICE | 检查服务代码、重复参数及多余参数。 |
| 400 | INVALID_PATH | 请求路径编码无效。 |
| 400 | INVALID_INPUT | 检查 JSON、字段类型、代码及额外参数。 |
| 400 | INVALID_MAX_PRICE | 限价格式无效,请传入大于零的十进制字符串。 |
| 401 | INVALID_API_KEY | 密钥缺失、格式不正确、已撤销或已重置。 |
| 404 | NOT_FOUND | 接口路径不存在。 |
| 403 | INVALID_ORIGIN | 不接受跨站 Origin;请从服务端调用。 |
| 404 | ORDER_NOT_FOUND | 订单不存在或不属于当前账户。 |
| 405 | METHOD_NOT_ALLOWED | 请使用接口标注的 HTTP 方法。 |
| 409 | IDEMPOTENCY_CONFLICT | 相同幂等键不能用于不同参数。 |
| 409 | MAX_PRICE_EXCEEDED | 暂无符合上限的可用价格,请调整限价或稍后重试。 |
| 409 | INSUFFICIENT_BALANCE / PRICE_UNAVAILABLE / PRICE_CHANGED / NO_NUMBERS | 检查余额、所选档位及库存;不自动加价。 |
| 409 | ORDER_BUSY / CANCEL_TOO_EARLY | 稍后查询或重试原订单,不创建新订单。 |
| 409 | ORDER_STATE_CONFLICT | 当前订单状态不允许此操作。 |
| 503 | PRICES_NOT_READY | 报价暂不可用,请稍后重试。 |
| 503 | STORAGE_UNAVAILABLE | 存储暂不可用,请退避重试。 |
| 503 | ORDER_STORAGE_UNAVAILABLE / ORDER_SERVICE_UNAVAILABLE | 结果未确认;保留原幂等键,查询原订单,勿重复扣费。 |
| 409 / 202 | ORDER_SERVICE_UNAVAILABLE / ORDER_REQUEST_REJECTED / ORDER_RESULT_UNCONFIRMED / ORDER_REVIEW_REQUIRED | 见 order.error 和订单状态;待核对不等于失败退款。 |
| 200 | ORDER_SMS_TEXT_UNAVAILABLE | 验证码已送达;短信全文暂不可用,请稍后查询。不可据此取消退款。 |
先检查 HTTP 状态,再解析响应。400、401 不应反复重试;网络异常与 503 可指数退避并加入随机延迟。网关错误可能返回非 JSON 内容。
每个账号默认同时处理最多 100 个取号请求,滚动 1 秒内最多接受 50 次创建请求;网页与 API 共用,管理员可单独调整。请求返回后释放并发,不限制持有的号码数量。超过限额返回 429 和 NUMBER_CONCURRENCY_LIMIT 或 NUMBER_RATE_LIMIT,Retry-After: 1;本次不会取号或扣款。降低频率,稍后保留原幂等键重试;查询、查码和取消不受此限额影响。
单个订单每 10 秒查询一次,终态停止轮询;网络异常保留原幂等键重试。取号不会超过 maxPrice。
接入约定
所有时间使用 UTC,金额使用十进制字符串,代码使用字符串。当前以轮询方式获取短信,不发送 Webhook。
充值请在登录后的充值页面操作,不提供 API 充值接口。
仅限经授权、合规的业务用途。不得用于绕过验证或规避平台反滥用措施。
打开工作台