← 所有文章
教程

UnifyPort 媒体发送:文件 URL 与送达问题排查

通过 UnifyPort 发送图片、视频、音频或文档时,使用 POST /v1/messages,设置渠道支持的 message.type,并在 message.url、message.file_url 或 message.file_key 中提供至少一个非空来源。URL 必须是完整的 HTTP(S) 地址。本地文件名不是可访问的媒体 URL,响应中的 status: accepted 也不代表收件人已收到文件。

先记住四个边界

  • 先检查消息账号所属渠道,再开放媒体类型选项。
  • 优先提供一个明确、可访问的 URL,不猜测多个来源字段的优先级。
  • 出站 message 与入站 data.message.attachments[] 不是同一请求结构。
  • 文件访问、请求校验、账号连接和最终送达应分别排查。

先确定使用哪套发送契约

UnifyPort 的非官方接口遵循媒体发送文档,不是 Telegram Bot API 或 LINE Messaging API。例如,Telegram 文件发送文档描述了其原生方法使用的文件标识、HTTP URL 和 multipart 上传;这不能证明 UnifyPort 将 Telegram file_id 作为 file_key 接受,也不能证明两者支持相同的上传请求。

字段UnifyPort 文档明确的含义
message.type媒体类型包括 image、video、audio、document、file,仍须检查渠道支持情况
message.url 或 message.file_url非空、完整的 HTTP(S) 来源地址
message.file_key已记录的另一种来源方式,不意味着可以自造 key 或上传端点
message.caption图片、视频、文档和文件可选的说明文字
provider_data.secondsWhatsApp 音频和视频可选的非负整数时长,单位为秒

WhatsApp 视频的时长取值范围为 0–4294967295;provider_data.waveform 仍仅用于音频。不要把入站 duration_ms 原样填进秒数字段。不需要时长时,宁可省略,也不要猜值。

当前消息能力矩阵未映射 TikTok 音频及文档/文件发送,将 X 音频标为部分支持,并分别列出 whatsapp-protocol 与 whatsapp。统一端点不等于每个渠道拥有相同能力和限制。面向东南亚的跨境团队也应按实际渠道控制发送界面。

构造请求前,先准备文件

以下是应用设计建议,不是新增的平台保证:

  1. 确认操作员有权使用所选账号向目标会话发送内容。群聊应使用会话 ID 和类型,而不是消息作者的 ID。
  2. 分别检查授权状态和 runtime_status;已授权不等于连接在线。
  3. 将正确的文件放在受控且可访问的来源中。浏览器登录后能打开的页面,不足以证明发送服务能取得文件。
  4. 从独立服务器环境、不携带浏览器 Cookie 测试读取,检查返回的是真实媒体,而不是 HTML 登录页或错误页。
  5. 使用限时 URL 时,为预计排队和读取时间安排有效期。发送文档未承诺统一的抓取截止时间;预检成功也不保证稍后仍可访问。

建议使用 HTTPS、最小访问范围和应用批准的存储来源。不要把签名查询参数或凭据写入日志。这些是安全建议,不代表 UnifyPort 存在某种未公开的网络过滤机制。

构造基于 URL 的媒体请求

下面的 JavaScript 函数使用应用已选定的账号、会话和获准媒体 URL 生成请求体。它不上传文件,也不验证远端实际可访问性。调用前仍须完成渠道能力和操作权限检查。

function buildMediaRequest({ accountId, conversation, type, url, caption }) {
  const types = new Set(['image', 'video', 'audio', 'document', 'file']);
  if (!accountId || !conversation?.id || !conversation?.type) {
    throw new Error('Account and conversation are required');
  }
  if (!types.has(type)) throw new Error('Unsupported media type');

  const source = new URL(url);
  if (!['http:', 'https:'].includes(source.protocol) ||
      source.username || source.password) {
    throw new Error('Use an approved HTTP(S) media source');
  }

  const message = { type, url: source.href };
  if (caption !== undefined) {
    if (type === 'audio' || typeof caption !== 'string') {
      throw new Error('Caption is not valid for this request');
    }
    message.caption = caption;
  }

  return {
    account_id: accountId,
    to: { id: conversation.id, type: conversation.type },
    message,
  };
}

将生成的 JSON 提交至 POST /v1/messages,在服务端使用 X-Api-Key 鉴权和 Content-Type: application/json。示例只提供 message.url:文档要求至少一个来源,但没有说明多个来源相互冲突时的优先级。

不要直接把收到的附件对象粘贴进发送请求。入站媒体字段指南中的 attachments[].type、url、mimetype 等是接收字段,不是完整出站请求。若原地址已经过期,先按下载链接恢复指南确认对应接口的恢复方式,再决定是否转发。

按失败环节排查

现象下一步检查不应采取的动作
提供了本地路径、相对地址或 data: URL准备完整 HTTP(S) 文件来源把路径改名成 file_key
只有自己的浏览器能打开登录依赖、有效期、重定向及响应内容假设发送方继承浏览器会话
unsupported_message_type渠道与媒体类型组合重复提交同一请求
provider_not_ready授权状态与运行状态未诊断便重新授权
请求超时保留出站操作记录,调查不确定结果自动重发,造成潜在重复消息
响应为 accepted保存返回标识,另查支持的送达证据立即显示“已送达”或“已读”

按错误参考中的机器可读错误分支处理,不要猜测错误描述文字。保留 request_id 供排查,但不要把它当作去重令牌;请求追踪指南进一步说明了这一边界。

处理回执时,查阅事件文档及渠道事件矩阵,验证 webhook 签名,并容忍重复和乱序。并非所有渠道都有每种回执,因此缺少确认应保留为未知,而不是触发再次发送。

验收检查与常见问题

上线前建议覆盖:可访问文件、已过期来源、返回登录页、不支持的渠道/类型组合、账号断连以及发送响应丢失。本文不声称已执行这些线上测试。

能通过这个 JSON 请求直接上传本地文件吗?

已记录的媒体请求使用 URL 或文件 key 来源。本文不提供或承诺 multipart 上传端点。请通过获准存储流程托管文件,再提供可访问 URL。

Telegram file_id 可以作为 file_key 吗?

文档没有建立这种对应关系。Telegram 原生文件标识与 UnifyPort 来源字段应分开处理。

accepted 代表对方收到文件了吗?

不代表。它表示请求已接受,而不是送达或已读回执。

下一步与参考资料

按发送图片和文件指南,先用一个获准测试会话和一个受控文件来源验证流程,再开放排队或自动发送。

参考资料核对日期:2026-10-09。

UnifyPort API

让消息接入变成一条稳定的产品管线。

先用统一 API 跑通发送,再用标准事件把所有入站消息接回业务系统。