API 参考

消息

发送文本消息

通过指定渠道账号发送标准化文本消息。message.text 必须非空;provider_data 承载 parse_mode 等渠道专属字段,引用回复使用顶层 reply_to。

POSThttps://api.unifyport.ai/v1/messages

支持的渠道

all

调用前准备

在服务端使用资源所属工作区的 X-Api-Key。运行示例前替换所有占位符。

完成所选授权流程并检查 runtime_status。授权与连接是两个状态,仅有 HTTP 成功不能证明账号已经就绪。

参数从哪里取得
account_id
从创建或查询账号的响应取得 data.id。账号标识属于 X-Api-Key 对应的工作区。 获取账号
to.id · to.type
回复消息时,将 message.received 中的 data.conversation.id 和 data.conversation.type 分别复制到 to.id、to.type。发送给新收件方时遵循对应渠道的标识规则。 统一消息发送能力

请求参数

请求头

X-Api-Key
string必填

工作区 API Key,工作区由该请求头解析得到。

Content-Type
string必填

发送 JSON 请求体时使用 application/json。

请求体

provider_data
object

渠道专属发送选项,仅在对应渠道和消息类型支持时生效。WhatsApp audio/video 的 seconds 使用非负整数;仅在 video 时使用 0 到 4294967295,waveform 仅适用于 audio。支持引用回复时请使用顶层 reply_to。sticker 的 provider_data 只能省略或为空对象;非对象返回 400 invalid_request,非空对象返回 400 provider_invalid_request。

seconds
integer

WhatsApp audio 或 video 消息的可选时长,单位为秒,使用非负整数;仅在 video 时,取值范围为 0 到 4294967295。

minimum: 0

waveform
string

WhatsApp audio 消息的可选音频波形数据。非空值必须使用标准 Base64 编码,且解码后必须是可解析的 JSON 波形数据;空字符串按未提供处理,其他格式错误返回 HTTP 400 provider_invalid_request。

account_id
string必填

发送该消息的渠道账号。

minLength: 1

to
object必填

收件方目标,包含 id 与 type。

id
string必填

收件方在渠道侧的标识。

minLength: 1

type
string必填

标准会话类型:user、group 或 channel。WhatsApp 社群公告群继续使用 group。

enum: user, group, channel

message
object必填

标准化消息载荷:文本使用 message.text,媒体使用 message.url。

type
string必填

消息类型:text、image、video、audio、document、file、contact、link_preview、poll 或 sticker。

enum: text, image, video, audio, document, file, contact, link_preview, poll, sticker

text
string

text 和 link_preview 必填的非空正文。link_preview 要求包含非空白字符;WhatsApp 还要求正文包含 link_preview.url 的原文。

minLength: 1

caption
string

image、video、document 或 file 消息的可选说明文字。

url
string

非空绝对 HTTP(S) 媒体 URL;媒体消息需在 url / file_url / file_key 中至少提供一个。

format: uri · pattern: ^[Hh][Tt][Tt][Pp][Ss]?://

file_url
string

非空备用绝对 HTTP(S) 媒体 URL;媒体消息需在三个来源字段中至少提供一个。

format: uri · pattern: ^[Hh][Tt][Tt][Pp][Ss]?://

file_key
string

非空渠道或存储文件引用;媒体消息需在三个来源字段中至少提供一个。

contacts[]
object[]

message.type=contact 时必填的非空结构化名片数组。

minItems: 1

name
string

每张名片必填的非空联系人显示名。

minLength: 1

phones[]
object[]

名片中包含的电话号码列表。

number
string

电话号码;每个 phone 条目都必须提供。

type
string

可选的电话类型,例如 CELL 或 WORK。

emails[]
object[]

名片中包含的电子邮箱列表。

address
string

电子邮箱地址;每个 email 条目都必须提供。

format: email

type
string

可选的邮箱类型,例如 WORK 或 HOME。

organization
string

联系人的可选组织名称。

title
string

联系人的可选职位名称。

link_preview
object

仅用于 message.type=link_preview,与 text 一起必填,不得混用其他载荷。公共结构仅要求 url;可选 title 和 description 允许空字符串,不允许 null。本 API 的 WhatsApp 发送策略额外要求非空 title/image_url,title 最多 255 个 Unicode 字符,description 最多 1024 个。

url
string

必填目标链接:带主机名且不含空白的绝对 HTTP(S) URI;方括号地址仅接受 IPv6 字面量。保留原文,不保证资源可访问。

pattern: ^[Hh][Tt][Tt][Pp][Ss]?://(?:[^/?#@\s]*@)?(?:\[[0-9A-Fa-f:.]+\]|[^/?#:@\s\[\]]+)(?::[0-9]*)?(?:[/?#]|$)

title
string

可选预览标题,允许空字符串,不允许 null。WhatsApp 要求非空,且最多 255 个 Unicode 字符。

description
string

可选预览摘要,允许空字符串,不允许 null。WhatsApp 最多允许 1024 个 Unicode 字符。

image_url
string

可选图片 URI,WhatsApp 要求必填且非空。必须是带主机名且不含空白的绝对 HTTP(S) URI;方括号地址仅接受 IPv6 字面量。保留原文,不保证资源可访问。

pattern: ^[Hh][Tt][Tt][Pp][Ss]?://(?:[^/?#@\s]*@)?(?:\[[0-9A-Fa-f:.]+\]|[^/?#:@\s\[\]]+)(?::[0-9]*)?(?:[/?#]|$)

poll
object

仅用于 message.type=poll 且必填;不得混用 text 或其他载荷。必须提供 question、options 和 max_selections。题目和选项标题保留原文。公共结构不限制题目长度、最大选项数量或标题重复;具体渠道可有额外限制。

question
string

必填投票题目,须包含非空白字符,保留原文。

minLength: 1 · pattern: \S

options[]
object[]

必填选项数组,至少两个选项,每项须有 title。

minItems: 2

title
string

必填选项标题,须包含非空白字符;发送时不 trim、不改大小写或 Unicode 形式。

minLength: 1 · pattern: \S

max_selections
integer

必填,每位投票者最多可选的选项数量,不是投票人数。必须为 1 到 options 数量之间的整数,由接口验证。1.0、1e0 等整数数值与 1 等价,非整数非法。

minimum: 1

reply_to
object

引用回复目标;把可引用消息事件的 data.message.reply_token 或发送响应的 data.reply_token 原样放入 reply_to.reply_token,使用原账号和会话,不可用消息 ID 替代。

reply_token
string

来自可引用消息事件 data.message.reply_token 或发送响应 data.reply_token 的不透明句柄;按原账号及会话原样使用,不可用消息 ID 替代。

minLength: 1

mentions[]
object[]

群消息的 @ 目标列表。type=member 使用对应 Provider 的成员 id;type=all 表示 @所有人,仅在 Provider 支持时生效,否则返回 unsupported_message_type。

type
string

@ 目标类型。省略时按 member 处理以兼容旧请求;type=member 必须传 id,type=all 不传 id 且仅适用于群聊。

enum: member, all

id
string

type=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
string

已受理消息的 UnifyPort 消息标识(msg_...)。

account_id
string

该响应所对应的渠道账号。

status
string

受理状态;accepted 表示消息已排队等待投递到渠道。

provider_ref
string

渠道侧消息引用,在渠道分配后返回。

reply_token
string

WhatsApp 发送成功且引用上下文完整时可选返回的非空不透明句柄,包括新发送投票,普通文字可据此引用。不可用时省略,不改变 accepted 状态。按原账号及会话原样使用,它不是消息 ID。

minLength: 1

响应

200

200 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"
  }
}