---
title: "短信API发送示例：Python、Node.js、PHP与cURL"
description: "用API发送短信的Python、Node.js、PHP和cURL示例：单条与批量发送、Unicode与阿拉伯语、分段计数、送达状态Webhook以及错误处理，开发者可直接复制使用。"
canonical: "https://omnichannels.ai/zh/blog/send-sms-api-examples/"
language: "zh"
updated: "2026-10-16"
publisher: "BroadNet Technologies"
brand: "OmniChannels.ai"
category: "integration"
primaryQuery: "短信API Python 发送示例"
keywords: ["Python发送短信", "Node.js短信API示例", "PHP短信API", "cURL短信API", "短信API Unicode 阿拉伯语", "短信送达报告Webhook", "批量短信API示例", "国际短信API"]
published: "2026-10-16"
author: "OmniChannels.ai Editorial Team"
reviewer: "BroadNet Messaging Solutions Team"
readingMinutes: 10
answer: "使用OmniChannels.ai API发送短信，需向https://api.broadnet.me/sms/sendSms发起带身份验证的POST请求，JSON请求体包含senderId、destinationNumber、message和messageType。GSM-7文本使用TEXT，阿拉伯语或emoji使用UNICODE。返回200时，响应体是纯文本的消息ID，最终送达状态稍后会推送到您的Webhook。"
takeaways: ["POST /sms/sendSms需要四个字段：senderId、destinationNumber、message和messageType；响应体是纯文本的消息ID，而不是JSON。", "阿拉伯语、emoji或任何GSM-7之外的字符，都要把messageType设为UNICODE；出现一个此类字符，整条消息就变成Unicode，每个分段也随之缩短。", "POST /sms/identify可在发送前统计字符数和分段数，让您预测一条消息会占用多少分段。", "送达是异步的：返回200仅表示已接受，DELIVERED、FAILED或REJECTED稍后会推送到您的Webhook。", "该API没有幂等键，所以请在发送前先记录每次发送，超时后检查状态，而不是重发。"]
faq: 
  - q: "如何用Python发送短信？"
    a: "使用requests库向https://api.broadnet.me/sms/sendSms POST JSON，带上Authorization: Bearer请求头以及senderId、destinationNumber、message和messageType字段。请从环境变量读取token。返回200时响应体是纯文本的消息ID，所以请使用r.text，而不是r.json()。"
  - q: "短信API要求什么样的手机号码格式？"
    a: "国家区号加国内号码，仅含数字，不带加号、00前缀、空格或前导零。例如447700900123有效，而+44 7700 900123和07700900123无效。请在自己的数据库中以E.164格式存储号码，并在构造请求时去掉加号。"
  - q: "如何通过API发送阿拉伯语短信？"
    a: "将messageType设为UNICODE，并以UTF-8在message字段中发送阿拉伯语文本。Unicode消息在单个分段中容纳70个字符，拆分后每段67个，而GSM-7分别为160和153个。请在真实手机上测试，并先调用/sms/identify查看分段数。"
  - q: "如何获取送达报告？"
    a: "状态会推送到您账户上配置的Webhook URL。消息依次经过SUBMITTED和SENT，最终到达DELIVERED、FAILED或REJECTED。您的端点应保存原始事件、快速返回2xx并异步处理。如果错过了事件，POST /sms/resendDlr可以按日期范围重新推送送达回执。"
  - q: "如何一次向很多号码发送短信？"
    a: "使用POST /sms/sendbulk，这是一个multipart请求，包含destinationNumberFile（CSV或TXT）和一个装有senderId、message和messageType的bulkRequest JSON字符串。响应会报告有效、无效和重复的号码数量，并返回一个bulkSessionId，您可以将其与营销活动一起存储。"
  - q: "需要注册发件人ID吗？"
    a: "在许多国家需要。有些国家要求已获批的字母数字发件人ID，另一些则需要监管机构或模板标识符，API通过peId和templateId等可选字段接受它们。要求因国家而异，请查看目的地的发件人ID页面，我们的团队也可以与您一起办理注册。"
sources: 
  - title: "3GPP TS 23.040：短消息服务（SMS）技术实现"
    url: "https://www.3gpp.org/dynareport?code=23040"
  - title: "ITU-T E.164：国际公共电信编号计划"
    url: "https://www.itu.int/rec/T-REC-E.164"
  - title: "RFC 9110：HTTP语义"
    url: "https://www.rfc-editor.org/rfc/rfc9110"
---

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

Canonical: https://omnichannels.ai/zh/blog/send-sms-api-examples/
Language: zh
Publisher: OmniChannels.ai by BroadNet Technologies

本指南面向需要从应用发送短信、并希望获得Python、Node.js、PHP或cURL可用代码的开发者。内容涵盖单条发送、Unicode和阿拉伯语、分段计数、批量上传、送达状态Webhook和错误处理，仅使用我们[短信API参考](/developers/sms/)和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` |

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

```bash
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"
  }'
```

```js
// 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
```

```python
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
<?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;
```

成功的响应体如下所示：

```text
2603121407537573731
```

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

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

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

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

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

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

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

```python
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与阿拉伯语短信指南](/zh/blog/sms-character-limits-unicode-arabic/)，并试用短信字符计数器。

## 发送前如何统计分段数？

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

```bash
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" }'
```

```json
{
  "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字符串。

```bash
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}'
```

```python
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查询指南](/zh/blog/hlr-lookup-number-validation/)。

## 如何接收送达状态？

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

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

```js
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`可以按日期范围重新推送回执：

```bash
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指南](/developers/webhooks/)和消息送达状态详解。

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

先处理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`。详情见[错误与限制](/developers/errors-and-limits/)。

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

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

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

## 常见错误有哪些？

- **对发送响应调用`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参考](/developers/sms/)或短信渠道。
