消息
发送文本消息
通过指定渠道账号发送标准化文本消息。message.text 必须非空;provider_data 承载 parse_mode 等渠道专属字段,引用回复使用顶层 reply_to。
https://api.unifyport.ai/v1/messages支持的渠道
调用前准备
在服务端使用资源所属工作区的 X-Api-Key。运行示例前替换所有占位符。
完成所选授权流程并检查 runtime_status。授权与连接是两个状态,仅有 HTTP 成功不能证明账号已经就绪。
请求参数
请求头
X-Api-Key工作区 API Key,工作区由该请求头解析得到。
Content-Type发送 JSON 请求体时使用 application/json。
请求体
provider_dataobject渠道专属发送选项,仅在对应渠道和消息类型支持时生效。WhatsApp audio/video 的 seconds 使用非负整数;仅在 video 时使用 0 到 4294967295,waveform 仅适用于 audio。支持引用回复时请使用顶层 reply_to。sticker 的 provider_data 只能省略或为空对象;非对象返回 400 invalid_request,非空对象返回 400 provider_invalid_request。
provider_data渠道专属发送选项,仅在对应渠道和消息类型支持时生效。WhatsApp audio/video 的 seconds 使用非负整数;仅在 video 时使用 0 到 4294967295,waveform 仅适用于 audio。支持引用回复时请使用顶层 reply_to。sticker 的 provider_data 只能省略或为空对象;非对象返回 400 invalid_request,非空对象返回 400 provider_invalid_request。
secondsWhatsApp audio 或 video 消息的可选时长,单位为秒,使用非负整数;仅在 video 时,取值范围为 0 到 4294967295。
minimum: 0
waveformWhatsApp audio 消息的可选音频波形数据。非空值必须使用标准 Base64 编码,且解码后必须是可解析的 JSON 波形数据;空字符串按未提供处理,其他格式错误返回 HTTP 400 provider_invalid_request。
account_id发送该消息的渠道账号。
minLength: 1
toobject必填收件方目标,包含 id 与 type。
to收件方目标,包含 id 与 type。
id收件方在渠道侧的标识。
minLength: 1
type标准会话类型:user、group 或 channel。WhatsApp 社群公告群继续使用 group。
enum: user, group, channel
messageobject必填标准化消息载荷:文本使用 message.text,媒体使用 message.url。
message标准化消息载荷:文本使用 message.text,媒体使用 message.url。
type消息类型:text、image、video、audio、document、file、contact、link_preview、poll 或 sticker。
enum: text, image, video, audio, document, file, contact, link_preview, poll, sticker
texttext 和 link_preview 必填的非空正文。link_preview 要求包含非空白字符;WhatsApp 还要求正文包含 link_preview.url 的原文。
minLength: 1
captionimage、video、document 或 file 消息的可选说明文字。
url非空绝对 HTTP(S) 媒体 URL;媒体消息需在 url / file_url / file_key 中至少提供一个。
format: uri · pattern: ^[Hh][Tt][Tt][Pp][Ss]?://
file_url非空备用绝对 HTTP(S) 媒体 URL;媒体消息需在三个来源字段中至少提供一个。
format: uri · pattern: ^[Hh][Tt][Tt][Pp][Ss]?://
file_key非空渠道或存储文件引用;媒体消息需在三个来源字段中至少提供一个。
contacts[]object[]message.type=contact 时必填的非空结构化名片数组。
minItems: 1
contacts[]message.type=contact 时必填的非空结构化名片数组。
minItems: 1
name每张名片必填的非空联系人显示名。
minLength: 1
phones[]object[]名片中包含的电话号码列表。
phones[]名片中包含的电话号码列表。
number电话号码;每个 phone 条目都必须提供。
type可选的电话类型,例如 CELL 或 WORK。
emails[]object[]名片中包含的电子邮箱列表。
emails[]名片中包含的电子邮箱列表。
address电子邮箱地址;每个 email 条目都必须提供。
format: email
type可选的邮箱类型,例如 WORK 或 HOME。
organization联系人的可选组织名称。
title联系人的可选职位名称。
link_previewobject仅用于 message.type=link_preview,与 text 一起必填,不得混用其他载荷。公共结构仅要求 url;可选 title 和 description 允许空字符串,不允许 null。本 API 的 WhatsApp 发送策略额外要求非空 title/image_url,title 最多 255 个 Unicode 字符,description 最多 1024 个。
link_preview仅用于 message.type=link_preview,与 text 一起必填,不得混用其他载荷。公共结构仅要求 url;可选 title 和 description 允许空字符串,不允许 null。本 API 的 WhatsApp 发送策略额外要求非空 title/image_url,title 最多 255 个 Unicode 字符,description 最多 1024 个。
url必填目标链接:带主机名且不含空白的绝对 HTTP(S) URI;方括号地址仅接受 IPv6 字面量。保留原文,不保证资源可访问。
pattern: ^[Hh][Tt][Tt][Pp][Ss]?://(?:[^/?#@\s]*@)?(?:\[[0-9A-Fa-f:.]+\]|[^/?#:@\s\[\]]+)(?::[0-9]*)?(?:[/?#]|$)
title可选预览标题,允许空字符串,不允许 null。WhatsApp 要求非空,且最多 255 个 Unicode 字符。
description可选预览摘要,允许空字符串,不允许 null。WhatsApp 最多允许 1024 个 Unicode 字符。
image_url可选图片 URI,WhatsApp 要求必填且非空。必须是带主机名且不含空白的绝对 HTTP(S) URI;方括号地址仅接受 IPv6 字面量。保留原文,不保证资源可访问。
pattern: ^[Hh][Tt][Tt][Pp][Ss]?://(?:[^/?#@\s]*@)?(?:\[[0-9A-Fa-f:.]+\]|[^/?#:@\s\[\]]+)(?::[0-9]*)?(?:[/?#]|$)
pollobject仅用于 message.type=poll 且必填;不得混用 text 或其他载荷。必须提供 question、options 和 max_selections。题目和选项标题保留原文。公共结构不限制题目长度、最大选项数量或标题重复;具体渠道可有额外限制。
poll仅用于 message.type=poll 且必填;不得混用 text 或其他载荷。必须提供 question、options 和 max_selections。题目和选项标题保留原文。公共结构不限制题目长度、最大选项数量或标题重复;具体渠道可有额外限制。
question必填投票题目,须包含非空白字符,保留原文。
minLength: 1 · pattern: \S
options[]object[]必填选项数组,至少两个选项,每项须有 title。
minItems: 2
options[]必填选项数组,至少两个选项,每项须有 title。
minItems: 2
title必填选项标题,须包含非空白字符;发送时不 trim、不改大小写或 Unicode 形式。
minLength: 1 · pattern: \S
max_selections必填,每位投票者最多可选的选项数量,不是投票人数。必须为 1 到 options 数量之间的整数,由接口验证。1.0、1e0 等整数数值与 1 等价,非整数非法。
minimum: 1
reply_toobject引用回复目标;把可引用消息事件的 data.message.reply_token 或发送响应的 data.reply_token 原样放入 reply_to.reply_token,使用原账号和会话,不可用消息 ID 替代。
reply_to引用回复目标;把可引用消息事件的 data.message.reply_token 或发送响应的 data.reply_token 原样放入 reply_to.reply_token,使用原账号和会话,不可用消息 ID 替代。
reply_token来自可引用消息事件 data.message.reply_token 或发送响应 data.reply_token 的不透明句柄;按原账号及会话原样使用,不可用消息 ID 替代。
minLength: 1
mentions[]object[]群消息的 @ 目标列表。type=member 使用对应 Provider 的成员 id;type=all 表示 @所有人,仅在 Provider 支持时生效,否则返回 unsupported_message_type。
mentions[]群消息的 @ 目标列表。type=member 使用对应 Provider 的成员 id;type=all 表示 @所有人,仅在 Provider 支持时生效,否则返回 unsupported_message_type。
type@ 目标类型。省略时按 member 处理以兼容旧请求;type=member 必须传 id,type=all 不传 id 且仅适用于群聊。
enum: member, all
idtype=member 时必填的 Provider 成员标识。
minLength: 1
如何理解结果
保存返回的 message_id 和 provider_ref,用于关联后续事件或排查。accepted 不表示已送达;仅在渠道支持回执时,通过对应事件确认送达。标识格式因渠道而异。
reply_token — WhatsApp 发送成功且引用上下文完整时可选返回的非空不透明句柄,包括新发送投票,普通文字可据此引用。不可用时省略,不改变 accepted 状态。按原账号及会话原样使用,它不是消息 ID。
响应 200 OK
{
"request_id": "<REQUEST_ID>",
"data": {
"message_id": "msg_example",
"account_id": "acc_example",
"status": "accepted",
"provider_ref": "provider_msg_example",
"reply_token": "<opaque WhatsApp reply handle>"
}
}
响应体
message_id已受理消息的 UnifyPort 消息标识(msg_...)。
account_id该响应所对应的渠道账号。
status受理状态;accepted 表示消息已排队等待投递到渠道。
provider_ref渠道侧消息引用,在渠道分配后返回。
reply_tokenWhatsApp 发送成功且引用上下文完整时可选返回的非空不透明句柄,包括新发送投票,普通文字可据此引用。不可用时省略,不改变 accepted 状态。按原账号及会话原样使用,它不是消息 ID。
minLength: 1
响应
200200 OK
请求成功,响应体示例如上。
400请求错误
请求体、路径或参数不合法。
401未授权
X-Api-Key 请求头缺失或无效。
403禁止访问
请求已识别,但不允许执行该操作。
404未找到
未找到请求的资源;请结合 error.code 和当前操作核对。
409冲突
当前操作与已有的渠道账号或资源冲突。
500服务端错误
服务端遇到了未预期的错误。
501渠道未实现
所选渠道尚未实现该操作。
502上游网关错误
渠道适配器或上游渠道未能完成该操作。
失败后怎么处理
检查 HTTP 状态和 error.code/numeric_code,保存 request_id 用于排查。按原因修正参数、继续授权或检查运行态。重试发送及其他写操作前先确认上一次结果,避免重复操作。 错误码参考
结合当前操作读取 HTTP 状态、error.code 和 error.numeric_code。数字码按字符串处理。保留 request_id 排障;它不是幂等键或任务标识。
- invalid_reply_token · 36006 · 400
无法读取引用令牌,请原样复制入站事件的 data.message.reply_token。
处理与重试: 按当前操作与渠道条件修正参数后再请求。重复提交相同的无效请求不会解决错误。
示意 JSON;message 随实际原因变化 · 400 · 36006
{ "request_id": "req_example", "error": { "code": "invalid_reply_token", "numeric_code": "36006", "message": "Invalid or unreadable reply_token" } }- invalid_request · 10000 · 400
检查 JSON 请求体和必填字段。
处理与重试: 按当前操作与渠道条件修正参数后再请求。重复提交相同的无效请求不会解决错误。
示例 · 400 · 10000
{ "request_id": "req_message_invalid_example", "error": { "code": "invalid_request", "numeric_code": "10000", "message": "Invalid message request body" } }- invalid_target_workspace · 11003 · 400
工作区覆盖目标为空或格式无效。移除覆盖请求头,改用目标工作区所属的 API Key。
触发条件: 适用于携带 X-Workspace-Id 工作区覆盖请求头的请求。
处理与重试: 按当前操作与渠道条件修正参数后再请求。重复提交相同的无效请求不会解决错误。
示意 JSON;message 随实际原因变化 · 400 · 11003
{ "request_id": "req_example", "error": { "code": "invalid_target_workspace", "numeric_code": "11003", "message": "Invalid target workspace" } }- provider_invalid_request · 30001 · 400
检查渠道专属字段及其格式。
处理与重试: 按当前操作与渠道条件修正参数后再请求。重复提交相同的无效请求不会解决错误。
示例 · 400 · 30001
{ "request_id": "req_sticker_rejected_example", "error": { "code": "provider_invalid_request", "numeric_code": "30001", "message": "sticker upload failed: media is unsupported" } }- provider_invalid_request · 36007 · 400
贴纸素材在调用渠道发送前校验失败。响应可提供具体准备原因;numeric_code=36007 不表示已尝试发送。
触发条件: 适用于调用渠道发送前,贴纸素材或其地址未通过校验的情况。
处理与重试: 按返回原因修正贴纸素材后再发送。此分类发生在素材准备、调用渠道发送之前,不能描述成可能已发送但结果未知。
示例 · 400 · 36007
{ "request_id": "req_sticker_invalid_example", "error": { "code": "provider_invalid_request", "numeric_code": "36007", "message": "invalid sticker media: invalid WebP container length" } }- unsupported_message_type · 36000 · 400
请使用此渠道支持的 message.type。
处理与重试: 选择文档列为支持的渠道与动作。重复请求不会增加能力或开通内测权限。
示意 JSON;message 随实际原因变化 · 400 · 36000
{ "request_id": "req_example", "error": { "code": "unsupported_message_type", "numeric_code": "36000", "message": "Message type not supported" } }- invalid_api_key · 11001 · 401
检查 API Key 是否正确且已启用。
处理与重试: 保留 request_id 与结构化错误码,先排查当前操作,再决定下一步。
示意 JSON;message 随实际原因变化 · 401 · 11001
{ "request_id": "req_example", "error": { "code": "invalid_api_key", "numeric_code": "11001", "message": "Invalid API key" } }- missing_api_key · 11000 · 401
请添加 X-Api-Key 请求头。
处理与重试: 保留 request_id 与结构化错误码,先排查当前操作,再决定下一步。
示例 · 401 · 11000
{ "request_id": "req_xxx", "error": { "code": "missing_api_key", "numeric_code": "11000", "message": "Missing X-Api-Key header" } }- workspace_override_forbidden · 11002 · 403
请求尝试使用此 API Key 无权使用的工作区覆盖。移除覆盖请求头,改用目标工作区所属的 API Key。
触发条件: 适用于携带 X-Workspace-Id 工作区覆盖请求头的请求。
处理与重试: 保留 request_id 与结构化错误码,先排查当前操作,再决定下一步。
示意 JSON;message 随实际原因变化 · 403 · 11002
{ "request_id": "req_example", "error": { "code": "workspace_override_forbidden", "numeric_code": "11002", "message": "Workspace override is not allowed" } }- target_workspace_not_found · 11004 · 404
覆盖指定的工作区不存在或不可用。核对工作区归属,移除覆盖请求头并使用目标工作区 API Key;重复请求不会增加访问权限。
触发条件: 适用于携带 X-Workspace-Id 工作区覆盖请求头的请求。
处理与重试: 核对目标标识、资源归属与当前工作区。不要把已确认缺失或无法访问的目标当作临时服务故障自动重试。
示意 JSON;message 随实际原因变化 · 404 · 11004
{ "request_id": "req_example", "error": { "code": "target_workspace_not_found", "numeric_code": "11004", "message": "Target workspace not found" } }- account_binding_not_found · 30006 · 409
账号尚无有效的渠道连接绑定,请检查账号状态。
处理与重试: 查询授权与运行态,再按目标状态和渠道支持选择刷新、启动或重连。连接问题本身不证明已登出;依赖连接的业务操作前确认 running。
示意 JSON;message 随实际原因变化 · 409 · 30006
{ "request_id": "req_example", "error": { "code": "account_binding_not_found", "numeric_code": "30006", "message": "Account is not bound to an available server" } }- provider_not_ready · 30009 · 409
连接尚未就绪,请检查授权及 runtime_status 后再决定是否重试。
处理与重试: 查询授权与运行态,再按目标状态和渠道支持选择刷新、启动或重连。连接问题本身不证明已登出;依赖连接的业务操作前确认 running。
示意 JSON;message 随实际原因变化 · 409 · 30009
{ "request_id": "req_example", "error": { "code": "provider_not_ready", "numeric_code": "30009", "message": "Provider client is not ready" } }- provider_not_ready · 30014 · 409
此账号所需的渠道实例缺失。这是运行实例可用性问题,不证明授权已过期。
处理与重试: 查询授权与运行态,再按目标状态和渠道支持选择刷新、启动或重连。连接问题本身不证明已登出;依赖连接的业务操作前确认 running。
适用渠道: WhatsApp
示意 JSON;message 随实际原因变化 · 409 · 30014
{ "request_id": "req_example", "error": { "code": "provider_not_ready", "numeric_code": "30014", "message": "Provider instance is missing" } }- provider_not_ready · 30015 · 409
渠道运行进程已停止。启动前确认这是否为预期状态;运行态停止本身不等于已登出。
处理与重试: 查询授权与运行态,再按目标状态和渠道支持选择刷新、启动或重连。连接问题本身不证明已登出;依赖连接的业务操作前确认 running。
适用渠道: WhatsApp
示意 JSON;message 随实际原因变化 · 409 · 30015
{ "request_id": "req_example", "error": { "code": "provider_not_ready", "numeric_code": "30015", "message": "Provider runtime is stopped" } }- send_message_failed · 20020 · 500
核对 account_id,并使用账号所属工作区的 X-Api-Key。此工作区下未找到的账号不能用当前 Key 访问。
触发条件: 适用于账号不存在的情况;保留原 HTTP 状态和操作 code,通过 numeric_code 细分账号缺失。
处理与重试: 核对目标标识、资源归属与当前工作区。不要把已确认缺失或无法访问的目标当作临时服务故障自动重试。
示意 JSON;message 随实际原因变化 · 500 · 20020
{ "request_id": "req_example", "error": { "code": "send_message_failed", "numeric_code": "20020", "message": "Account not found" } }- send_message_failed · 30010 · 500
渠道未能完成本次操作。message 可能在 “Provider operation failed:” 后附带原始原因;原因文本可变,不是稳定的程序接口。
触发条件: 适用于渠道未提供更具体失败分类的情况,保留当前操作的错误。
处理与重试: 再次发送前先确认原消息或回复是否已创建。超时或失败响应可能留下未知结果;后续查询未找到回复也不证明从未写入。不要自动重发。
适用渠道: WhatsApp
示意 JSON;message 随实际原因变化 · 500 · 30010
{ "request_id": "req_example", "error": { "code": "send_message_failed", "numeric_code": "30010", "message": "Provider operation failed" } }- send_message_failed · 36001 · 500
消息发送失败或结果无法确认。
处理与重试: 再次发送前先确认原消息或回复是否已创建。超时或失败响应可能留下未知结果;后续查询未找到回复也不证明从未写入。不要自动重发。
示例 · 500 · 36001
{ "request_id": "req_sticker_prepare_failed_example", "error": { "code": "send_message_failed", "numeric_code": "36001", "message": "download sticker: media download returned HTTP 503" } }- unsupported_by_provider · 30003 · 501
渠道不支持此操作,请选择能力表中支持的操作。
处理与重试: 选择文档列为支持的渠道与动作。重复请求不会增加能力或开通内测权限。
示例 · 501 · 30003
{ "request_id": "req_xxx", "error": { "code": "unsupported_by_provider", "numeric_code": "30003", "message": "Operation not supported by this provider" } }- provider_adapter_not_found · 30004 · 502
渠道服务暂不可用,请检查状态或稍后再试;重试写操作前先确认上次结果。
处理与重试: 再次发送前先确认原消息或回复是否已创建。超时或失败响应可能留下未知结果;后续查询未找到回复也不证明从未写入。不要自动重发。
示意 JSON;message 随实际原因变化 · 502 · 30004
{ "request_id": "req_example", "error": { "code": "provider_adapter_not_found", "numeric_code": "30004", "message": "Provider adapter unavailable" } }- provider_unavailable · 20102 · 502
WhatsApp 同步发送识别到账号登录受限,返回 HTTP 502、provider_unavailable、20102。WhatsApp 失败事件中同一数字语义使用 account_restricted;本次 HTTP 响应本身不会修改账号状态或新增回调。
处理与重试: 停止自动发送与重试,引导用户前往官方 WhatsApp 客户端检查并处理限制。问题解决并完成必要的重新授权后再恢复;此前为 running 不证明限制已解除。
适用渠道: WhatsApp
示例 · 502 · 20102
{ "request_id": "req_example_whatsapp_account_restricted", "error": { "code": "provider_unavailable", "numeric_code": "20102", "message": "Account login is restricted. Check the official WhatsApp app for details." } }- provider_unavailable · 30002 · 502
渠道服务暂不可用,请检查状态或稍后再试;重试写操作前先确认上次结果。
处理与重试: 再次发送前先确认原消息或回复是否已创建。超时或失败响应可能留下未知结果;后续查询未找到回复也不证明从未写入。不要自动重发。
示例 · 502 · 30002
{ "request_id": "req_example_provider_unavailable", "error": { "code": "provider_unavailable", "numeric_code": "30002", "message": "Provider service unavailable" } }- provider_unavailable · 30010 · 502
渠道未能完成本次操作。message 可能在 “Provider operation failed:” 后附带原始原因;原因文本可变,不是稳定的程序接口。
处理与重试: 再次发送前先确认原消息或回复是否已创建。超时或失败响应可能留下未知结果;后续查询未找到回复也不证明从未写入。不要自动重发。
适用渠道: WhatsApp
示例 · 502 · 30010
{ "request_id": "req_example_message_failed", "error": { "code": "provider_unavailable", "numeric_code": "30010", "message": "Provider operation failed: Example operation could not be completed" } }- provider_unavailable · 30019 · 502
平台明确限制本次消息发送,返回 HTTP 502、provider_unavailable、30019。不代表已确认账号永久封禁,也没有固定解限时间。
处理与重试: 对此类消息限制停止自动重试。确认平台限制解除后才恢复发送;没有固定解限时间,也不应仅凭此错误重新授权。
适用渠道: WhatsApp
示例 · 502 · 30019
{ "request_id": "req_example_message_restricted", "error": { "code": "provider_unavailable", "numeric_code": "30019", "message": "Message sending is restricted by the platform" } }- provider_unavailable · 30020 · 502
whatsapp-protocol 同步请求以 numeric_code=30020 标识账号登录受限,可影响会话导入、运行态、发送与联系人查询,并保留当前操作的 HTTP 状态与 code。不要将 WhatsApp 的 20102 回调契约套用到此渠道。
处理与重试: 停止自动发送与重试,引导用户前往官方 WhatsApp 客户端检查并处理限制。问题解决并完成必要的重新授权后再恢复;此前为 running 不证明限制已解除。
适用渠道: WhatsApp Protocol
示例 · 502 · 30020
{ "request_id": "req_example_account_restricted", "error": { "code": "provider_unavailable", "numeric_code": "30020", "message": "Account login is restricted. Check the official WhatsApp app for details." } }- provider_unavailable · 30021 · 502
本次操作时 WhatsApp 未建立连接,message 保留原始连接原因。这不证明已登出或授权失效,也不会自动重连、重发或修改账号状态。
处理与重试: 暂停依赖连接的业务操作。先调用 POST /v1/accounts/{account_id}/runtime/refresh,按最新状态恢复,确认 runtime_status=running 后再请求业务接口。重发前确认上一次写入结果。
适用渠道: WhatsApp
示例 · 502 · 30021
{ "request_id": "req_example_connection_disconnected", "error": { "code": "provider_unavailable", "numeric_code": "30021", "message": "example operation: websocket not connected" } }- provider_unavailable · 34012 · 502
WhatsApp 群消息要求当前账号具备管理员权限。请先调整群内角色,不要原样重试。
处理与重试: 保留 request_id 与结构化错误码,先排查当前操作,再决定下一步。
适用渠道: WhatsApp
示例 · 502 · 34012
{ "request_id": "req_example_group_admin_required", "error": { "code": "provider_unavailable", "numeric_code": "34012", "message": "Group administrator privileges are required to send messages to this group" } }