> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wtocrm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# WTOCRM WhatsApp API 发送消息：curl 与 Node.js 实操

> 用 curl 或 Node.js 发送第一条 WhatsApp API 消息，了解 REST endpoint 完整地址、文本与媒体及模板消息的选择，并排查 401 和 429。

**用 WTOCRM 发送 WhatsApp 消息，需要向 `https://waapi.wtocrm.com/message/sendText/{instanceName}` 发起 POST 请求，在 `apikey` 请求头中传入密钥，并在请求体中提供收件号码与 `textMessage.text`。** 下方示例从后端调用已连接的实例，不需要 SDK。

如果你在为 SaaS 添加客户通知，或为客户搭建自动化流程，先确认一条消息能到达你自己的测试手机，再扩展附件、回调与受控重试。

> **接入要点**
>
> * 向 `/message/sendText/{instanceName}` 发送 JSON POST 请求，用 `apikey` 鉴权。
> * 先创建并连接实例。获取二维码或配对码不代表已经连接成功。
> * 媒体上传、已批准的业务模板和 `wa.me` 链接解决的是不同任务。
> * 401 先修正凭证；429 先检查响应并降低请求压力。重试前核实结果不确定的发送是否已完成。

![后端模块、半透明网关和手机通过一条消息路径连接的概念插画](https://assets.wtocrm.com/blog/2026/send-whatsapp-message-api/cover-e5bfbefd61.webp)

后端通过 API 网关向手机发送消息的概念插画，不是真实产品截图。

## 用 curl 或 Node.js 发送第一条文本消息

执行示例前，先[创建实例](https://docs.wtocrm.com/zh-Hans/waapi/create-instance.md)，通过[二维码或配对码连接账号](https://docs.wtocrm.com/zh-Hans/waapi/connect-instance.md)，再调用[连接状态接口](https://docs.wtocrm.com/zh-Hans/waapi/get-connection-state.md)，确认 `instance.state` 为 `open`。这些步骤适用于 WTOCRM 关联设备协议接入，与 Meta 官方 WhatsApp Business Platform／Cloud API 的接入流程分别处理。

准备带有 curl 的终端；JavaScript 示例使用 Node.js 22 或更高版本，调用 Node 自带的 [`fetch`](https://nodejs.org/docs/latest-v22.x/api/globals.html#fetch)。密钥保留在后端。在运行示例的同一个终端设置以下变量，替换全部三个占位值：

```bash theme={null}
export WTO_API_KEY='YOUR_API_KEY'
export WTO_INSTANCE='YOUR_CONNECTED_INSTANCE'
export WTO_TO='COUNTRY_CODE_AND_YOUR_TEST_NUMBER'
```

收件号码填写你自己的 WhatsApp 测试号码，包含国家码，只保留数字，不带 `+`、空格或标点。这些变量只为示例提供参数，不会创建或连接实例。正式应用通过已有的密钥管理机制注入凭证。

### curl：一次 POST 请求

[文本消息接口文档](https://docs.wtocrm.com/zh-Hans/waapi/send-text-message.md)定义了以下请求结构：

```bash theme={null}
curl --request POST "https://waapi.wtocrm.com/message/sendText/${WTO_INSTANCE}" \
  --header "apikey: ${WTO_API_KEY}" \
  --header 'Content-Type: application/json' \
  --data "{\"number\":\"${WTO_TO}\",\"textMessage\":{\"text\":\"WTOCRM API test\"}}"
```

完成准备后，这就是发送固定测试文本的最小请求。文档记录的成功响应为 HTTP `200`，响应字段包括 `key`、`message` 和 `status`。检查实际返回内容，并在收件手机上确认消息；接口响应不能代替最终送达验证。

### Node.js：使用原生 fetch，不安装 SDK

将下方代码保存为 `send-message.mjs`，在已设置变量的终端中执行 `node send-message.mjs`：

```javascript theme={null}
const response = await fetch(`https://waapi.wtocrm.com/message/sendText/${encodeURIComponent(process.env.WTO_INSTANCE)}`, {
  method: 'POST',
  headers: { apikey: process.env.WTO_API_KEY, 'Content-Type': 'application/json' },
  body: JSON.stringify({ number: process.env.WTO_TO, textMessage: { text: 'WTOCRM API test' } })
});
const body = await response.text();
if (!response.ok) throw new Error(`HTTP ${response.status}: ${body}`);
console.log(body);
```

服务器返回 401 或 429 时，`fetch` 不会仅因状态码就抛出异常。显式检查 `response.ok`，才能把这些响应交给错误处理逻辑。排查时可在受限的开发日志中保留完整响应；分享日志前去除凭证、号码及消息内容。

## 看懂 REST endpoint 与完整 URL

接口由 HTTP 方法和 URL 共同确定操作。WTOCRM 文本发送请求需要以下部分配合：

| 部分 | 值 | 作用 |
| - | - | - |
| 方法 | `POST` | 提交消息操作 |
| API 基础地址 | `https://waapi.wtocrm.com` | 访问 WTO WA API 服务 |
| 路径 | `/message/sendText/{instanceName}` | 为指定实例选择文本发送操作 |
| 鉴权 | `apikey` 请求头 | 提供有权访问该实例的密钥 |
| JSON 请求体 | `number`、`textMessage.text` | 指定收件人与消息 |

替换 `{instanceName}`，不要把花括号原样发送。这里填实例名，不是收件号码。在浏览器直接打开 URL 通常会发出 GET，而且没有所需的请求头和 JSON 请求体，因此不会执行该 POST 发送操作。

这个 URL 和请求结构属于 WTOCRM。不要把它与其他提供方的 Bearer Token 示例、Graph API 路径或请求字段混用。本指南由 [WTOCRM](https://wtocrm.com) 发布；各处链接的产品文档定义当前请求约定。

\*\*示例验证方法：\*\*2026 年 11 月 3 日，我们使用 Node.js v24.22.2，在本地 HTTP 模拟服务上检查了 curl 和 Node.js 示例。检查范围包括请求路径、`apikey`、文本 JSON、multipart 上传，以及 Node 对 HTTP 200/401/429 的处理。测试没有向真实 WhatsApp 发送消息。

## 选择文本、媒体或模板消息

根据内容和已连接的渠道选择消息类型，不要不断更换 endpoint 来碰运气。

| 类型 | 适用内容 | WTOCRM 参考路径 | 先检查什么 |
| - | - | - | - |
| 文本 | 普通文字回复或测试消息 | `/message/sendText/{instanceName}` | 实例已连接，JSON 字段符合文档 |
| 媒体 | 报价 PDF、图片、视频或音频附件 | `/message/sendMedia/{instanceName}` | 文件上传格式与媒体类型 |
| 模板 | 在要求使用已批准模板的业务渠道发送通知 | `/message/sendTemplate/{instanceName}` | 渠道支持、模板批准状态及提供方所需参数 |

### 使用 multipart 表单上传媒体

当前[媒体消息文档](https://docs.wtocrm.com/zh-Hans/waapi/send-media-message.md)要求提供 `number`、`mediatype` 和二进制 `media` 文件。假设你已在当前目录准备好自己的 `quote.pdf`：

```bash theme={null}
curl --request POST "https://waapi.wtocrm.com/message/sendMedia/${WTO_INSTANCE}" \
  --header "apikey: ${WTO_API_KEY}" \
  --form "number=${WTO_TO}" \
  --form 'mediatype=document' \
  --form 'media=@./quote.pdf;type=application/pdf'
```

让 curl 设置 multipart 的 boundary，不要沿用文本示例的 `Content-Type: application/json`。文档支持的媒体类型是 `image`、`video`、`audio` 和 `document`，还提供可选的 `caption`、`fileName` 字段。此示例上传本地文件，没有假设 `media` 字段能直接接收远程 URL。

### 实现前确认模板能力

已批准的业务模板与应用中保存的一段可复用文本不同。当你选择的业务渠道要求通知使用已批准的消息格式时，使用对应模板。`wa.me` 链接和普通文本请求都不能代替模板批准流程。

WTOCRM 列出了[模板消息接口](https://docs.wtocrm.com/zh-Hans/waapi/send-template-message.md)，但当前公开请求结构只展示 `number` 和 `textMessage.text`，没有定义已批准模板的名称、语言或组件映射，也没有明确哪些连接模式支持此操作。实现前确认具体渠道和模板请求参数；把 `sendText` 改成 `sendTemplate` 不是已验证的转换方法。

如果你要配置 WTOCRM 的官方 Cloud API 渠道，请使用独立的 [WhatsApp 渠道配置指南](https://docs.wtocrm.com/zh-Hans/user-guides/channels/whatsapp-setup.md)。不要假定本例使用的扫码关联实例具有相同的模板流程与能力。

## 区分 WhatsApp API link 的三种含义

“WhatsApp API 链接”可能指三种不同入口。先判断由谁打开，以及希望执行什么动作。

| 含义 | 示例或入口 | 作用 |
| - | - | - |
| REST API 接口 | `https://waapi.wtocrm.com/message/sendText/{instanceName}` | 后端提交结构化消息请求 |
| 点击聊天链接 | `https://wa.me/<international-number>?text=<encoded-text>` | 用户打开聊天窗口，可预填文字，并自行决定是否发送 |
| 账号或渠道绑定入口 | WTOCRM 连接指南或渠道设置 | 账号持有人关联设备或授权所选渠道 |

使用 `wa.me` 时，填写不带 `+` 或标点的完整国际号码，并对可选文字进行 URL 编码。这个链接不会为后端鉴权，也不会自动发送消息。

关联设备时，`GET /instance/connect/{instanceName}` 用于请求二维码或配对信息，账号持有人仍需完成手机端操作。渠道绑定链接是接入入口，不是通用发送地址。保护登录二维码和配对码，按文档引导账号持有人完成连接。

## 排查 401 和 429，避免重复发送

先记录 HTTP 状态、响应头和响应体。排查时，在前面的 curl 请求中加入 `--include`；Node 中检查 `response.status`、`response.headers` 和 `body`。分享请求记录前去除个人信息。

### 401：修正鉴权后再试

WTOCRM 文本和媒体接口将 401 定义为凭证缺失或无效。检查 `WTO_API_KEY` 是否已设置，请求头是否为 `apikey`，密钥是否属于目标环境并有权访问目标实例。如果请求经过代理，还要确认代理转发了该请求头。

缺少实例名属于另一类路由问题。这些接口将 HTTP 403 定义为权限不足，404 则可能表示实例不存在。重复发送相同的未授权请求无法解决这些问题。

### 429：降低请求压力，按响应等待

[HTTP 429](https://www.rfc-editor.org/rfc/rfc6585.html#section-4)表示一段时间内请求过多。标准允许响应包含 `Retry-After`，但没有要求一定提供。如果服务返回该字段，遵守其中的等待时间；否则使用有最大间隔、随机抖动和有限次数的退避重试，并通过队列限制并发。

WTOCRM 发送文档目前没有公布 429 响应约定或固定的每秒请求额度。这里介绍的是实际 API 链路、网关或提供方返回 429 时的通用处理方法。结合响应体和响应头识别来源，不套用其他提供方的数字限制，也不要假定重试可以绕过账号限制。

自动化工作室需要协调共享同一账号或服务额度的任务进程。多个进程同时独立重试，会让请求压力持续居高不下。保留原始任务标识，超过设定的重试预算后停止。

### 分清参数错误、超时和送达问题

| 结果 | 下一步 |
| - | - |
| `400` | 按对应文档检查请求体、号码格式和媒体表单字段 |
| `403` | 检查密钥权限，不把它当作临时限流 |
| `404` | 检查基础地址、路径和实例名 |
| 超时或响应丢失 | 先确认发送是否已完成，再决定是否重新提交 |
| API 响应成功，手机未收到 | 检查连接状态和可用消息事件，记录实际结果 |

不要假定 API 提供幂等请求头：当前发送文档没有记录这种能力。你的应用应保存任务和可用的返回消息标识，对结果不确定的操作先核对再重发。仅有本地任务编号，无法阻止网络结果不明确后再次调用产生第二次发送。

## 验证一条消息，再接入业务流程

第一次测试应确认三件事：接口响应、测试手机收到的消息，以及回复是否进入应用。按 [Webhook 配置文档](https://docs.wtocrm.com/zh-Hans/waapi/set-webhook.md)选择实例支持的事件，并将回调关联到正确的实例和联系人。

只向同意接收消息的收件人发送。把连接故障与鉴权故障分开处理，在增加任务进程或客户前验证重试行为。

**打开 [WTOCRM API 接入指南](https://docs.wtocrm.com/zh-Hans/waapi/connect-instance.md)**，连接实例，确认 `open`，再执行第一条文本发送请求。


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.