开发者

公开 API Beta

使用安全、限定权限的 API 密钥和稳定的版本化 JSON 约定构建工作区集成。

打开交互式 API 参考

快速入门

  1. 01

    打开 API 密钥

    打开设置,选择开发者,找到 API 密钥,然后选择创建密钥。所有者和管理员可以创建密钥。

  2. 02

    创建 API 密钥

    填写名称,选择有效天数,将渠道访问权限设为全部渠道或指定渠道,并在权限范围下选择集成所需的最少权限。只有当密钥具备端点所要求的确切资源操作时,请求才会成功。选择创建密钥。

  3. 03

    保存你的 API 密钥

    完整密钥只显示一次。把它复制到你的密钥管理工具中,然后选择我已保存。

  4. 04

    发送密钥

    使用 Bearer 令牌,或在 x-api-key 中发送相同的值。切勿把密钥放在查询字符串或浏览器代码中。

cURL

curl https://www.usesonny.com/api/v1/contacts?limit=25 \
  --header "Authorization: Bearer sonny_your_key"

密钥始终安全

密钥安全
密钥使用 sonny_ 前缀和 64 个随机字符,存储时经过单向哈希,有效期可配置,每个密钥每分钟限 600 次请求。一个密钥只绑定一个工作区。
要撤销某个密钥,选择它旁边的删除按钮。在撤销 API 密钥?中选择删除确认。密钥会立即停用。
每次调用都进行授权
Sonny 会校验哈希和权限范围,然后重新检查创建者当前的工作区成员身份、角色和账单状态。移除或停用该用户会立即禁用其所有密钥。
每次 REST API 和 MCP 调用都会强制执行所选渠道限制。联系人、属性、标签和 Webhook 管理端点需要全部渠道的访问权限。从表单创建对话时,可在指定渠道上使用 contacts:write 配合 conversations:write;独立的联系人端点仍作用于整个工作区。

权限范围

  • contacts:read
  • contacts:write
  • tags:read
  • tags:write
  • conversations:read
  • conversations:write
  • messages:read
  • messages:write
  • messages:send
  • webhooks:read
  • webhooks:write
  • kb:read
  • kb:write
  • csat:read
  • attachments:write
  • members:read
  • contact-memory:read
  • contact-memory:write
  • reporting:read

资源

联系人
管理联系人、带类型的属性、精确值筛选和客户记忆。可以归档联系人,或在处理数据保护请求时将其连同所有对话永久删除。
来源
查看已配置的来源,以及每个来源支持聊天、邮件还是两者皆可。
对话
从表单创建咨询、筛选待处理对话、分配客服或团队、延后、打标签和批量更新。
同步
使用保存的游标重放持久的工作区变更和删除记录。
成员与团队
查看可分配的同事、在线状态和实际的渠道访问权限。
报表
读取客服、团队、AI、知识库、潜在客户和在线时长报表。
消息
读取消息历史和附件提取内容,上传私有文件,添加内部备注,以及发送或编辑给客户的回复。
Webhook
管理端点、订阅、测试、投递和重试。
知识库
按来源创建、读取、更新和删除帮助中心文章与分类。
客户满意度
读取工作区、各渠道和各对话的满意度得分,并按评分值、评论、负责人或时间范围筛选列出单条评分。

从 AI 工具中使用 Sonny

Sonny MCP 将每一项公开 API 操作都作为工具提供。客户端通过 OAuth 2.1 登录(或使用限定权限的 API 密钥)进行连接,每次调用都遵循同样的权限范围、工作区边界和业务规则。

阅读 Sonny MCP 指南

响应与错误

集合类响应使用 data,并在适用时包含分页信息。每个响应都包含 x-request-id;你也可以提供一个安全的请求 ID,Sonny 会原样返回。错误会返回安全的提示信息,不会暴露敏感的实现细节。

{
  "error": {
    "type": "validation_error",
    "message": "Invalid email address",
    "requestId": "req_01J..."
  }
}
400
输入、JSON、查询参数或游标无效。
401
API 密钥缺失、无效、已过期或缺少权限范围。
402
工作区的账单状态阻止了此请求。
403
密钥创建者在工作区中的角色无权执行此操作。
404
该资源在密钥所属的工作区中不存在。
409
请求与现有资源冲突。
410
同步游标已过期。请重新获取当前状态,并从新游标开始重放。
413
上传内容超出允许的大小。
422
该来源没有邮件渠道,或提交的字段值无效。
429
超出了单个密钥的请求频率限制。
500
发生意外错误。请携带请求 ID 重试。
503
Webhook 投递积压已满,请稍后重试。

请求频率限制

每个 API 密钥每分钟最多可发起 600 次请求。每个响应都会通过标准的 RateLimit-Limit、RateLimit-Remaining 和 RateLimit-Reset 响应头报告当前时间窗口,客户端可以据此自行限流,而不必猜测。超出限制时,API 返回 429 和 Retry-After 响应头——请等待相应的秒数后再重试。

版本与弃用

API 通过 URL 路径进行版本控制(/api/v1)。同一版本内只做增量变更——新增端点、新增可选字段、新增枚举值。破坏性变更会以新版本发布;任何 v1 端点下线前,我们都会提前至少六个月通知:在本页面公告、通过邮件通知拥有有效 API 密钥的工作区所有者,并在受影响的端点上返回 Deprecation 和 Sunset 响应头。

编辑已发送的回复

  1. 为你的 API 密钥或 MCP 连接授予 messages:read 和 messages:send 权限范围,以及该回复所在渠道的访问权限。
  2. 读取对话的消息,并复制你发送的一条人工回复的 ID。API 密钥以其创建者的身份操作;OAuth 以已连接的同事身份操作。
  3. 使用下面的请求发送替换文本,或在 MCP 中调用 edit_message,并传入 conversationId、messageId 和 body。
  4. 检查返回的消息。它的 ID、附件、已读回执和原始发送时间都保持不变。
curl --request PATCH \
  https://www.usesonny.com/api/v1/conversations/conversation_1/messages/message_1 \
  --header "Authorization: Bearer sonny_your_key" \
  --header "Content-Type: application/json" \
  --data '{"body":"The corrected reply"}'

编辑会更正对话记录和已连接的聊天客户端。它不会再次发送邮件或通知,已送达的邮件也保持不变。只能编辑你自己发给客户的人工回复;收到的消息、机器人回复、内部备注和其他同事的回复都无法编辑。请等待待发送的邮件投递完成后再编辑。替换文本必须包含 1–50,000 个字符;之前的 HTML 和链接预览会被清除。集成会收到 message.updated Webhook 和同步事件。只轮询更新的消息 ID 无法发现编辑;请使用持久同步流。

从表单创建对话

将表单提交发送到 POST /api/v1/conversations。Sonny 会按邮箱查找或创建联系人,保存表单答案,并在你所选来源的邮件渠道上打开一个收到的对话。该渠道的团队、分配规则和通知都会生效。客服通过邮件回复。

  1. 创建一个具有 conversations:write 和 contacts:write 的密钥。你可以将其限制在客户的指定渠道。通过 GET /api/v1/sources 查找来源 ID,这还需要 conversations:read。
  2. 在 n8n 中添加一个 HTTP Request 节点:方法 POST,URL https://www.usesonny.com/api/v1/conversations。将密钥保存在 Header Auth 凭据中:Authorization,值为 Bearer sonny_your_key。
  3. 启用 Send Body,选择 JSON 和 Using JSON,然后把整个 JSON 字段切换为 Expression 并粘贴此示例。替换来源 ID,并把输入字段映射到你的表单。请使用表单稳定且唯一的提交 ID,这样重试时会使用相同的值。
{{ {
  sourceId: "YOUR_CLIENT_SOURCE_ID",
  contact: { email: $json.email, name: $json.name },
  subject: "Website enquiry",
  message: $json.message,
  fields: {
    Company: String($json.company ?? ""),
    Budget: String($json.budget ?? ""),
    Service: String($json.service ?? "")
  },
  externalId: "website-form-" + $json.submissionId
} }}

更多节点选项请参阅 n8n HTTP Request 指南。对应的 MCP 工具是 create_conversation,负载和权限相同。

新的字段名会成为文本属性。已有的数字、URL、日期和选项字段必须收到有效的字符串值;值无效时会返回 422 并指出字段名,且不会保存任何内容。日期接受 ISO 日期或时间戳;选项值必须与某个选项匹配。最多接受 50 个字段,字段名最长 100 个字符,值最长 5,000 个字符。属性会显示在联系人和对话侧边栏中。即使你提供了可选的 htmlMessage,两种消息正文中也都会保留一份答案副本。

可选的 tags 最多接受 20 个现有的工作区标签 ID。响应包含 conversation、contact 摘要、message 和 deduplicated。新提交返回 201。在同一来源上重复使用 externalId 会返回 200、原有 ID 以及 deduplicated: true;变更的内容会被忽略。不提供外部 ID 时,每次调用都会创建新对话。创建时不支持附件和 AI 自动回复。

智能体工作流

分拣、处理,并保持同步

REST 和 MCP 共用相同的权限和工作流。凭据只能缩小你当前的渠道访问范围;从你的成员身份中移除某个渠道,也会把它从你的集成中移除。

找出需要处理的对话

可按 awaitingReply、unread、unassigned、assigneeId、agentGroupId、snoozed、priority 或 tagIds 筛选。等待回复会忽略内部备注;未读针对的是已认证的同事本人。未分配表示没有个人负责人,即使已分配给某个团队。标签匹配所提供的任意 ID。

GET /api/v1/conversations?status=open&awaitingReply=true&compact=true&sort=waitingSince&direction=asc

可按 waitingSince、lastMessageAt、createdAt 或业务优先级排序,方向为 asc 或 desc,ID 用于决定并列顺序。省略筛选条件时保持 compact=false 和 snoozed=any。REST 的 tagIds 接受逗号分隔的 ID;MCP 还接受数组。waitingSince 从上次回复之后的第一条收到的消息开始计算;后续消息和内部备注不会重置它。即使没有收到 Webhook,也请定期运行这种等待队列扫描,让旧会话重新浮现。

无需重读收件箱即可追上进度

使用 GET /api/v1/sync 并授予 conversations:read。持久变更流包含对话变更、标签、消息、联系人属性、记忆和删除记录。每种负载还需要各自的读取权限:消息正文需要 messages:read,记忆需要 contact-memory:read。受限的凭据只会收到其被允许的渠道。

  1. 不带游标开始,沿着 nextCursor 一直读取到 hasMore 为 false,然后保存该游标。
  2. 读取当前的对话和联系人列表,以及初始状态所需的任何历史记录。
  3. 从保存的游标开始重放,捕获读取期间发生的变更。处理完每一页后,保存 nextCursor。

按事件 id 去重:重放至少投递一次,因此下游操作需要自己的防重复机制。不带游标的请求只覆盖最近一小时,并非完整快照。事件保留 30 天;HTTP 410 resync_required 表示需要重新初始化。扩大权限范围或渠道访问后也需要重新初始化。limit 最大为 100,maxBodyChars 最大为 10,000(默认 500)。设置 compact=true 可获得上限为 200 个字符的消息 textPreview/textTruncated 字段,而不是 body/bodyTruncated。Webhook 可以唤醒智能体;即使没有 Webhook 订阅或 Webhook 投递积压,变更流依然可用。

检查只做一次,结果共享

在重复调查之前,先读取 list_conversation_checks(GET /api/v1/conversations/{conversationId}/checks)。使用 record_conversation_check(PUT 到同一路径)保存结果,提供 key、result、checkedBy,以及可选的 reference(卡片 ID 或 URL)。例如:key=product-version、result=Shopstar Go verified、checkedBy=Engineer、reference=card-X。Sonny 会记录已认证的 actorId 和 checkedAt 时间戳。重复使用某个 key 只会替换该项检查;这是当前状态,而不是历史日志。读取需要 conversations:read,写入需要 conversations:write,二者都限定在对话所属的渠道。这些调用不会发送回复,也不会把卖家标记为已回复。

批量分配和更新工作

通过 GET /api/v1/members and /teams(members:read)查看活跃的、可分配的同事和团队。响应包含在线状态和实际的渠道访问权限,但不含邮箱地址。使用 conversations:write 更改 status、priority、assigneeId、agentGroupId、snoozedUntil、snoozedUntilReply、addTagIds 或 removeTagIds。

POST /api/v1/conversations/batch
{
  "conversationIds": ["conversation_1", "conversation_2"],
  "updates": { "agentGroupId": "team_1", "assignment": "round_robin" }
}

轮流分配会选择一位在线、且能访问该对话渠道的团队成员。没有符合条件的成员时,单个更新返回 409,批量中的对应项失败。每个批量最多接受 100 个不重复的 ID,并对每个对话原子地应用一次补丁。请检查每一个 { id, ok, error? } 结果;部分项可能会失败。批量操作按当前基于请求的频率限制计算,不按项目数量加权计费。

与 Sonny AI 共享客户信息

使用 contact-memory:read/write 列出、保存和删除联系人记忆。需同时提供 contactId 和一个可访问的 sourceId;该联系人必须在此来源上有对话。保存的事实与应用内使用相同的校验、去重处理和限制,并记录为手动记忆。

在 /api/v1/properties 读取属性定义,在 /api/v1/contacts/{contactId}/properties 读取或设置属性值。MCP 提供 list_properties、get_contact_properties 和 set_contact_property。这些操作需要 contacts:read/write 以及全部渠道的访问权限。只设置 propertyId 或 propertyName 其中之一,值为字符串,或用 null 清除。文本、数字、URL、日期和选项值都会根据字段定义进行校验。

PUT /api/v1/contacts/contact_1/properties
{ "propertyName": "Plan", "value": "Pro" }

GET /api/v1/contacts?property[Plan]=Pro

属性筛选匹配精确存储的字符串;多个属性必须全部匹配。通过 API 写入的值会在 Co-Pilot 和自动回复中标注为 API 数据。现有的已验证客户和来源规则依然适用。普通的手动内部字段值仍不会纳入此 AI 上下文。

读取与团队相同的报表

授予 reporting:read 后调用 GET /api/v1/reporting/{kind}。报表类型有 overview、volume、response-times、agents、sources、tags、csat、ai、knowledge、leads 和 online-hours。overview 综合了数量、响应时间和满意度。筛选条件包括 period(1–365 天,默认 30)、成对的 from/to 日期(to 不包含在内)、granularity(day/month)、source、assigneeId 和 tagId。source 接受 all、all-chat、all-email、website:{id} 或 email:{id}。

报表使用与仪表板相同的查询和当前的访问检查。knowledge 报表按日期和被允许的渠道统计,不受所选来源、负责人或标签影响。online-hours 衡量可访问同事在工作区中的在线时长;其中的对话数量仍按渠道限定。现有的 /csat 端点保留单独的 csat:read 权限范围,统计对象可能不同。

在回复或内部备注中发送文件

授予 attachments:write,并为某个对话上传最大 25 MB 的文件。POST /api/v1/attachments 接受 multipart 格式的 file 和 conversationId 字段。响应包含 id 和 expiresAt。在一小时内,最多可将 10 个 attachmentIds 传给一条回复或备注。每次上传都绑定到你的用户和该对话,且只能使用一次。未使用的上传会在过期后清理。

POST /api/v1/conversations/conversation_1/reply
{ "attachmentIds": ["upload_1"] }

回复需要 messages:send;内部备注需要 messages:write,且永远不会发给客户。支持只含附件的消息。邮件回复会在邮件大小限制内附上文件,其余文件则提供下载链接;离线聊天邮件会包含文件链接。只要附件还在,邮件中的链接就一直可用,收件人可以稍后打开。转发邮件会共享这些文件的访问权限。请检查 emailDeliveryStatus 了解投递失败情况。

经授权的消息读取包含 downloadUrl、downloadExpiresAt、aiStatus、aiDescription 和 aiExtractedText,链接视频(Loom、Vimeo 等)还包含 videoTranscripts。下载链接有效期为 15 分钟;需要新链接时请重新读取消息。新的 API/MCP 上传使用私有存储。较早的附件仍为公开,并标记为 access=legacy_public:其原始 URL 不会过期。当工作区开通了 Sonny AI 时,读取消息会触发读取其中的图片。图片识别和视频文字稿会在消息到达后不久完成:若仍有任务在运行,响应会以 readsInProgress 开头,其中的 nextStep 给出了应调用的确切操作。传入 waitSeconds(最多 30)可在一次请求中等待它们完成。面向客户的聊天组件和实时消息永远不会包含提取内容或文字稿。

查看完整的请求与响应约定

知识库

从外部来源同步

使用稳定的外部 ID 同步文章和分类,导入 Markdown 或 HTML,上传图片,设置排序,并管理读者受众。重复执行 upsert 会更新已有内容。

  1. 选择你渠道的 sourceId,并授予 kb:read 和 kb:write。将 API 密钥保存在你的服务器上,并限制其渠道访问权限。
  2. 先创建分类,再将文章作为草稿同步。发布前检查其格式和访问权限。
  3. 配置帮助中心访问权限、发布,并测试读者视图。之后的更新请使用分页和稳定的外部 ID。
按照完整的 REST 同步教程操作

管理客户受众

根据已验证的客户特征创建群组,并应用到帮助中心、分类或文章。所有继承的限制都必须满足。API 和 MCP 凭据在其权限范围内以员工身份操作;请预览并测试真实的客户会话,以检查读者访问权限。

设置并测试帮助中心受众

相关文档