跳转到正文
OmniChannels.ai

短信API发送示例:Python、Node.js、PHP与cURL

用API发送短信的Python、Node.js、PHP和cURL示例:单条与批量发送、Unicode与阿拉伯语、分段计数、送达状态Webhook以及错误处理,开发者可直接复制使用。

更新于 10 分钟阅读

作者: OmniChannels.ai Editorial Team · 审阅: BroadNet Messaging Solutions Team

集成

简短回答

使用OmniChannels.ai API发送短信,需向https://api.broadnet.me/sms/sendSms发起带身份验证的POST请求,JSON请求体包含senderId、destinationNumber、message和messageType。GSM-7文本使用TEXT,阿拉伯语或emoji使用UNICODE。返回200时,响应体是纯文本的消息ID,最终送达状态稍后会推送到您的Webhook。

本页内容
  1. 如何用API发送短信?
  2. 手机号码应当使用什么格式?
  3. 如何发送阿拉伯语、emoji或其他Unicode文本?
  4. 发送前如何统计分段数?
  5. 如何发送给大量号码?
  6. 如何接收送达状态?
  7. 如何处理错误并避免重复发送?
  8. 实战示例:区域应用的登录验证码
  9. 常见错误有哪些?
  10. OmniChannels.ai 如何提供帮助

要点速览

  • POST /sms/sendSms需要四个字段:senderId、destinationNumber、message和messageType;响应体是纯文本的消息ID,而不是JSON。
  • 阿拉伯语、emoji或任何GSM-7之外的字符,都要把messageType设为UNICODE;出现一个此类字符,整条消息就变成Unicode,每个分段也随之缩短。
  • POST /sms/identify可在发送前统计字符数和分段数,让您预测一条消息会占用多少分段。
  • 送达是异步的:返回200仅表示已接受,DELIVERED、FAILED或REJECTED稍后会推送到您的Webhook。
  • 该API没有幂等键,所以请在发送前先记录每次发送,超时后检查状态,而不是重发。

本指南面向需要从应用发送短信、并希望获得Python、Node.js、PHP或cURL可用代码的开发者。内容涵盖单条发送、Unicode和阿拉伯语、分段计数、批量上传、送达状态Webhook和错误处理,仅使用我们短信API参考和OpenAPI规范中的端点和字段。

如何用API发送短信?

向/sms/sendSms发起带身份验证的POST请求,请求体为JSON。响应为200 OK,消息ID以纯文本形式返回。

项目 值
基础URL https://api.broadnet.me(无/v1前缀)
端点 POST /sms/sendSms
鉴权 Authorization: Bearer $BROADNET_TOKEN
内容类型 application/json
必填字段 senderId、destinationNumber、message、messageType

测试凭证在提交简短的访问申请后发放,测试发送只发往您自己已验证的号码。目前没有即时自助注册。请参阅快速入门。

curl -X POST https://api.broadnet.me/sms/sendSms \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "senderId": "OmniDemo",
    "destinationNumber": "447700900123",
    "message": "Your OmniDemo code is 482913",
    "messageType": "TEXT"
  }'
// Node.js 18+(内置fetch)
const res = await fetch("https://api.broadnet.me/sms/sendSms", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.BROADNET_TOKEN}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    senderId: "OmniDemo",
    destinationNumber: "447700900123",
    message: "Your OmniDemo code is 482913",
    messageType: "TEXT",
  }),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const messageId = await res.text(); // 纯文本的消息ID
import os
import requests

r = requests.post(
    "https://api.broadnet.me/sms/sendSms",
    headers={"Authorization": f"Bearer {os.environ['BROADNET_TOKEN']}"},
    json={
        "senderId": "OmniDemo",
        "destinationNumber": "447700900123",
        "message": "Your OmniDemo code is 482913",
        "messageType": "TEXT",
    },
    timeout=15,
)
r.raise_for_status()
message_id = r.text  # 纯文本的消息ID,不是JSON
<?php
$payload = json_encode([
    "senderId" => "OmniDemo",
    "destinationNumber" => "447700900123",
    "message" => "Your OmniDemo code is 482913",
    "messageType" => "TEXT",
]);

$ch = curl_init("https://api.broadnet.me/sms/sendSms");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 15,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("BROADNET_TOKEN"),
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => $payload,
]);
$messageId = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
echo $status . " " . $messageId . PHP_EOL;

成功的响应体如下所示:

2603121407537573731

请把这个ID与您自己的记录(如订单或登录尝试)一起保存。之后就靠它来匹配送达状态。

手机号码应当使用什么格式?

使用国家区号加国内号码,仅含数字。格式遵循ITU-T E.164国际编号计划,但不带加号。

输入 是否有效 原因
447700900123 有效 国家区号44加国内号码
+44 7700 900123 无效 请去掉加号和空格
07700900123 无效 请把前导0替换为国家区号

请在数据库中以E.164格式(+447700900123)存储号码,并在构造请求时去掉+。我们的免费手机号码格式化工具可以帮助快速检查。

如何发送阿拉伯语、emoji或其他Unicode文本?

将messageType设为UNICODE。任何GSM-7字母表之外的字符,例如阿拉伯字母、emoji、弯引号或破折号,都会让整条消息切换为Unicode。

r = requests.post(
    "https://api.broadnet.me/sms/sendSms",
    headers={"Authorization": f"Bearer {os.environ['BROADNET_TOKEN']}"},
    json={
        "senderId": "OmniDemo",
        "destinationNumber": "971500000000",
        "message": "رمز التحقق الخاص بك هو 482913",
        "messageType": "UNICODE",
        "campaignName": "login-otp",
    },
    timeout=15,
)

在PHP中,调用json_encode时请使用JSON_UNESCAPED_UNICODE。编码决定分段大小,这是3GPP TS 23.040对短信的定义:

messageType 单条短信 拆分时每段 适用场景
TEXT 160个字符 153个字符 仅使用GSM-7字母表的文本
UNICODE 70个字符 67个字符 阿拉伯语、西里尔字母、中文、emoji

大多数运营商按分段计费,所以较长的阿拉伯语消息比同样长度的拉丁字母消息更贵。请阅读我们的Unicode与阿拉伯语短信指南,并试用短信字符计数器。

发送前如何统计分段数?

使用消息调用POST /sms/identify。它会返回检测到的编码、字符数、分段数和每段上限。

curl -X POST https://api.broadnet.me/sms/identify \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "message": "Your OmniDemo code is 482913" }'
{
  "message": "Your OmniDemo code is 482913",
  "messageType": "TEXT",
  "smscount": 1,
  "charCount": 28,
  "charLimit": 160
}

您可以把smsParts(来自smscount)、charCount和charLimit传入发送请求。GSM-7文本在响应中可能被标记为GSM-7;发送时请使用TEXT。

如何发送给大量号码?

使用POST /sms/sendbulk,这是一个multipart/form-data请求,包含一个收件人文件和一个设置的JSON字符串。

curl -X POST https://api.broadnet.me/sms/sendbulk \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -F destinationNumberFile=@recipients.csv \
  -F 'bulkRequest={"senderId":"OmniDemo","message":"Your statement is ready in the app.","messageType":"TEXT","campaignName":"oct-statements","allowDuplicate":false}'
import json
import os
import requests

bulk_request = {
    "senderId": "OmniDemo",
    "message": "Your statement is ready in the app.",
    "messageType": "TEXT",
    "campaignName": "oct-statements",
    "allowDuplicate": False,
}

with open("recipients.csv", "rb") as f:
    r = requests.post(
        "https://api.broadnet.me/sms/sendbulk",
        headers={"Authorization": f"Bearer {os.environ['BROADNET_TOKEN']}"},
        files={"destinationNumberFile": ("recipients.csv", f, "text/csv")},
        data={"bulkRequest": json.dumps(bulk_request)},
        timeout=60,
    )
print(r.json())

响应中包含bulkSessionId和一个带有total、validCount、invalidCount和duplicate的bulkListInfo对象。请把bulkSessionId与营销活动一起存储。任务可以通过参考文档中的端点列出、暂停、恢复和中止。您也可以在大批量发送之前,用POST /sms/lookup检查号码;请参阅我们的HLR查询指南。

如何接收送达状态?

送达状态会推送到您账户上配置的Webhook URL。一条消息依次经过SUBMITTED和SENT到达DELIVERED,或者以FAILED或REJECTED结束。您把公开的HTTPS URL提供给我们的团队即可,转售商可以为每个子账户设置一个Webhook。

负载字段因渠道而异,API规范也没有定义单一的Webhook结构,所以请先记录原始请求体,再根据您账户上的真实事件映射字段。一个最简接收端只需保存事件并迅速确认:

import express from "express";

const app = express();

app.post("/webhooks/omnichannels", express.json(), async (req, res) => {
  await saveStatusEvent(req.body); // 您自己的存储;异步处理
  res.sendStatus(200);             // 尽快确认
});

app.listen(3000);

请让处理具备幂等性,因为同一状态可能到达两次,并且绝不要让迟到的SENT覆盖已存储的DELIVERED。如果您的端点曾经宕机,POST /sms/resendDlr可以按日期范围重新推送回执:

curl -X POST https://api.broadnet.me/sms/resendDlr \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "startDate": "2026-10-09",
    "endDate": "2026-10-10",
    "senderId": "OmniDemo",
    "messageStatus": "DELIVERED"
  }'

更多内容请阅读Webhook指南和消息送达状态详解。

如何处理错误并避免重复发送?

先处理HTTP状态,再看错误响应体。只对网络错误、429和5xx重试。

状态码 含义 操作
200 已接受 保存ID
400 校验错误或缺少字段 修正请求
401 / 403 token错误或操作不被允许 修正;不要重试
429 超出速率限制 等待Retry-After
500、503、504 服务端或上游故障 采用退避和抖动重试

API抛出的错误使用包含status、error、message、errorCode和requestUri五个字段的JSON响应体。文档中记载的REST默认限制为持续每秒200个请求;您账户的具体限制会随凭证一并确认。

该API不接受幂等键。一个请求可能成功但响应丢失,盲目重试就会发送两次。请在调用之前,先以您自己的操作ID为键写入一条待处理行,保存返回的消息ID,并在超时后先检查Webhook状态,再决定是否重发。批量发送时,请把allowDuplicate设为false。详情见错误与限制。

实战示例:区域应用的登录验证码

“Souq Rafiq”(虚构)是阿联酋的一家零售商,通过短信发送登录验证码。

  1. 认证服务生成六位验证码,存储带五分钟有效期的哈希,并写入一条pending发送记录。
  2. 它调用/sms/sendSms,阿拉伯语用户使用messageType=UNICODE,英语用户使用TEXT。
  3. 返回200时,保存消息ID。
  4. Webhook处理程序把该记录标记为DELIVERED、FAILED或REJECTED。
  5. 如果短暂等待后状态仍不是DELIVERED,应用会提供重发选项,并在配置的情况下提供另一个渠道。请参阅渠道回退。
  6. 按号码和按IP限制验证码请求频率,可防止滥用;请参阅短信泵送防范。

常见错误有哪些?

  • **对发送响应调用r.json()。**它是纯文本。
  • **字段名错误。**请使用senderId、destinationNumber和message;to、from或text等字段不属于该端点。
  • 号码中带有加号和前导零。
  • 阿拉伯语**忘记使用UNICODE,**导致文本乱码。
  • **未注册的发件人ID。**有些国家会封堵或替换它们;请查看目的地的发件人ID规则,并让我们来办理注册。
  • 把200当作已送达。
  • **把token放在移动应用或浏览器中,**任何人都能提取。
  • **局限:**本指南展示的是常见请求。定时发送格式等可选字段,请与我们的团队确认。

OmniChannels.ai 如何提供帮助

OmniChannels.ai通过BroadNet的运营商直连发送A2P短信,支持双向短信、发件人ID、Unicode和阿拉伯语、HLR查询,并提供用于大批量的SMPP 3.4。位于https://api.broadnet.me的REST API使用Bearer token,同时覆盖WhatsApp、RCS和其他渠道,送达状态统一为一种Webhook格式。我们的团队与您一起准备发件人ID注册。请查看短信API参考或短信渠道。

常见问题

如何用Python发送短信?

使用requests库向https://api.broadnet.me/sms/sendSms POST JSON,带上Authorization: Bearer请求头以及senderId、destinationNumber、message和messageType字段。请从环境变量读取token。返回200时响应体是纯文本的消息ID,所以请使用r.text,而不是r.json()。

短信API要求什么样的手机号码格式?

国家区号加国内号码,仅含数字,不带加号、00前缀、空格或前导零。例如447700900123有效,而+44 7700 900123和07700900123无效。请在自己的数据库中以E.164格式存储号码,并在构造请求时去掉加号。

如何通过API发送阿拉伯语短信?

将messageType设为UNICODE,并以UTF-8在message字段中发送阿拉伯语文本。Unicode消息在单个分段中容纳70个字符,拆分后每段67个,而GSM-7分别为160和153个。请在真实手机上测试,并先调用/sms/identify查看分段数。

如何获取送达报告?

状态会推送到您账户上配置的Webhook URL。消息依次经过SUBMITTED和SENT,最终到达DELIVERED、FAILED或REJECTED。您的端点应保存原始事件、快速返回2xx并异步处理。如果错过了事件,POST /sms/resendDlr可以按日期范围重新推送送达回执。

如何一次向很多号码发送短信?

使用POST /sms/sendbulk,这是一个multipart请求,包含destinationNumberFile(CSV或TXT)和一个装有senderId、message和messageType的bulkRequest JSON字符串。响应会报告有效、无效和重复的号码数量,并返回一个bulkSessionId,您可以将其与营销活动一起存储。

需要注册发件人ID吗?

在许多国家需要。有些国家要求已获批的字母数字发件人ID,另一些则需要监管机构或模板标识符,API通过peId和templateId等可选字段接受它们。要求因国家而异,请查看目的地的发件人ID页面,我们的团队也可以与您一起办理注册。

资料来源

  1. 3GPP TS 23.040:短消息服务(SMS)技术实现
  2. ITU-T E.164:国际公共电信编号计划
  3. RFC 9110:HTTP语义