开发者中心HTTPS · JSON · UTF-8

API 文档

从取号到收码,一条清晰的接入路径。

查询账户与库存,创建号码订单,轮询短信并管理订单状态。

BASE URLhttps://beansms.app

创建订单前请确认余额充足。maxPrice 为最高接受单价,实际扣费不会超过该上限。

01

身份验证

账户及订单接口需要 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,重试原请求时保持不变。

02

账户信息

GET/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"]
}
响应字段
字段类型说明
userIdinteger五位用户 ID
labelstring账户标签
balanceobjectUSD 余额,以十进制字符串返回,最多三位小数。
scopesstring[]account:read, orders:read, orders:write
03

服务与国家目录

GET/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" }
  ]
}

代码按字符串处理,名称仅用于展示。目录存在某个服务或国家,不代表当前有库存。

04

库存与报价

GET/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 }
      ]
    }
  ]
}
响应字段
字段类型说明
priceTypestringsale:返回价格为可用于取号的售价。
currencystring | null统一币种;混合币种或无报价时为 null,以每档 currency 为准。
updatedAt / expiresAtISO 8601报价更新时间与到期时间,均为 UTC。
stale / syncFailedboolean任一值为 true 时建议刷新报价;库存不保证实时可用。
rows[].countrystring目录中的国家代码
rows[].cost / stockstring / 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'])
05

取号与短信

创建号码订单

POST/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"}'
请求参数
字段类型说明
servicestring必填,目录中的服务代码。
countrystring必填,目录中的国家代码。
maxPricestring可选,最高接受单价(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。示例值仅说明格式。

查询订单与短信

GET/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"
  }
]

完成与取消

POST/api/v1/orders/{id}/completeBearer
POST/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,稍后重试原订单。

06

错误处理

HTTP 400
Content-Type: application/json

{"error":"INVALID_SERVICE"}
接口错误码
HTTPerror说明
400INVALID_SERVICE检查服务代码、重复参数及多余参数。
400INVALID_PATH请求路径编码无效。
400INVALID_INPUT检查 JSON、字段类型、代码及额外参数。
400INVALID_MAX_PRICE限价格式无效,请传入大于零的十进制字符串。
401INVALID_API_KEY密钥缺失、格式不正确、已撤销或已重置。
404NOT_FOUND接口路径不存在。
403INVALID_ORIGIN不接受跨站 Origin;请从服务端调用。
404ORDER_NOT_FOUND订单不存在或不属于当前账户。
405METHOD_NOT_ALLOWED请使用接口标注的 HTTP 方法。
409IDEMPOTENCY_CONFLICT相同幂等键不能用于不同参数。
409MAX_PRICE_EXCEEDED暂无符合上限的可用价格,请调整限价或稍后重试。
409INSUFFICIENT_BALANCE / PRICE_UNAVAILABLE / PRICE_CHANGED / NO_NUMBERS检查余额、所选档位及库存;不自动加价。
409ORDER_BUSY / CANCEL_TOO_EARLY稍后查询或重试原订单,不创建新订单。
409ORDER_STATE_CONFLICT当前订单状态不允许此操作。
503PRICES_NOT_READY报价暂不可用,请稍后重试。
503STORAGE_UNAVAILABLE存储暂不可用,请退避重试。
503ORDER_STORAGE_UNAVAILABLE / ORDER_SERVICE_UNAVAILABLE结果未确认;保留原幂等键,查询原订单,勿重复扣费。
409 / 202ORDER_SERVICE_UNAVAILABLE / ORDER_REQUEST_REJECTED / ORDER_RESULT_UNCONFIRMED / ORDER_REVIEW_REQUIRED见 order.error 和订单状态;待核对不等于失败退款。
200ORDER_SMS_TEXT_UNAVAILABLE验证码已送达;短信全文暂不可用,请稍后查询。不可据此取消退款。

先检查 HTTP 状态,再解析响应。400、401 不应反复重试;网络异常与 503 可指数退避并加入随机延迟。网关错误可能返回非 JSON 内容。

每个账号默认同时处理最多 100 个取号请求,滚动 1 秒内最多接受 50 次创建请求;网页与 API 共用,管理员可单独调整。请求返回后释放并发,不限制持有的号码数量。超过限额返回 429 和 NUMBER_CONCURRENCY_LIMIT 或 NUMBER_RATE_LIMIT,Retry-After: 1;本次不会取号或扣款。降低频率,稍后保留原幂等键重试;查询、查码和取消不受此限额影响。

单个订单每 10 秒查询一次,终态停止轮询;网络异常保留原幂等键重试。取号不会超过 maxPrice。

07

接入约定

所有时间使用 UTC,金额使用十进制字符串,代码使用字符串。当前以轮询方式获取短信,不发送 Webhook。

充值请在登录后的充值页面操作,不提供 API 充值接口。

仅限经授权、合规的业务用途。不得用于绕过验证或规避平台反滥用措施。

打开工作台