Warmbly文档

端点权限范围表

列出所有端点、各端点接受的身份验证类型,以及所需权限。

本页是判断 API 密钥可访问和不可访问哪些内容的权威依据。后端的所有路由均属于以下三类之一:

  • 支持 API 密钥:既可使用 JWT(控制台用户),也可使用具有所列权限的 API 密钥。
  • 仅支持 JWT:API 密钥永远无法访问。用于计费、治理、WebSocket 初始化、危险区域中的销毁操作、OAuth 接入流程及管理工具。
  • 公开端点:无需身份验证(带签名验证的 Webhook、健康检查、OAuth 跳转页面)。

端点标注“JWT permission: X / API permission: Y”时,同时支持 JWT 和 API 密钥的身份验证中间件会根据调用者使用的凭据检查相应权限。

仅限访问 选定资源 的成员,无论使用何种凭据,都只能访问少量读取路由,且结果仅限于获授权资源:GET /campaigns、/campaigns-overview、/campaigns/:id 及其 /logs、/steps 和 /ab-variants、GET /analytics/dashboard(其 campaign_ids 和 folder_ids 筛选条件必须指向获授权的营销活动和文件夹)、/analytics/campaigns/compare、/analytics/campaigns/:id 及其 /daily 和 /hourly、GET /analytics/accounts 和 /analytics/accounts/:id、GET /emails 和 /emails/:id,以及统一收件箱读取路由 GET /unibox、/unibox/count、/unibox/overview、/unibox/thread、/unibox/thread/labels、/unibox/scheduled 和 /unibox/:id(对这些成员而言,该路由不会将邮件标记为已读)。其自身账户相关路由 /auth/*、/me/*、GET /organization、/organization/current、/organization/switch/:id、/invitations、GET /subscription、/subscription/features、GET /timezones 和 POST /getaway 仍可使用。其他所有路由均返回 403 member_access_restricted,未获授权的营销活动或邮箱返回 404。API 密钥自身的邮箱允许列表还会叠加生效:密钥只能访问同时出现在两份列表中的邮箱。

下方所有路径均相对于带版本的基础 URL https://api.warmbly.com/v1(例如 /campaigns 表示 https://api.warmbly.com/v1/campaigns)。详见 版本管理。

受限响应数据与工作区策略

  • GET /organization/current 返回受限摘要:total_campaigns 和 active_campaigns 统计获授权营销活动;total_contacts 统计这些活动中的去重联系人;email_accounts 统计获授权邮箱;emails_sent_today 统计同时属于获授权营销活动和获授权邮箱的已确认营销活动发送。member_count、product_description、icp_notes 和 voice_profile 会省略。非受限响应保持原有工作区整体结构。
  • GET /analytics/dashboard 在返回 scope.campaign_count 前,会将营销活动和文件夹筛选条件与授权范围取交集。
  • GET /campaigns/:id/logs 保留分页和营销活动动态,但受限响应使用安全消息及显式选定的元数据。未获邮箱授权范围内的邮箱地址、上限、跨营销活动发送状态、预热健康信息及账户 ID 均被移除。不暴露跟踪域名、原始服务商错误、未知字段或嵌套元数据。仅授予营销活动访问权,并不意味着授予其发件邮箱访问权。
  • 对于受限成员,GET /auth/me 和 /unibox/overview 仅包含应用于可访问邮箱内邮件的分类。非受限成员仍获得工作区分类登记表。收件箱访问基于邮箱:授予共享邮箱访问权,也会开放其中其他营销活动的会话。
  • GET /unibox/thread/labels 在列出标签之前,会检查所选组织及实际生效的邮箱允许列表中是否存在相应邮件。未知、跨工作区和不可访问的会话均返回相同的 404。可访问但没有标签的会话返回空列表。
  • GET /emails 仅在所选组织及实际生效的邮箱允许列表范围内解析分页游标。超出任一边界的游标不会为分页提供时间戳。

工作区创建和限额申请路由是上述路由级拒绝规则的例外:它们在服务层验证账户或目标工作区的权限。POST /organization 对所有成员关系均受限的账户返回 403 member_access_restricted,实例管理员除外。没有成员关系,或至少有一个非受限成员关系的账户,仍受现有创建限制约束。提交或列出 /organization/:orgId/limit-requests,以及删除 /limit-requests/:id,要求在请求的目标组织中拥有非受限成员关系。切换当前选定工作区无法绕过这些检查。

工作区通知和按资源所有者寻址的实时投递也会检查当前组织成员关系。仅拥有资源并不足以授权接收工作区级事件。受限、已移除和尚未接受邀请的成员不会收到工作区通知,包括持久化动态和延迟邮件/推送投递。个人登录安全通知仍可接收。已打开资源通道的 30 秒刷新上限,参见 实时授权与撤销。

这些检查在托管和自托管实例上均使用现有授权,无需新增迁移或配置。现有非受限访问行为保持不变。

支持 API 密钥

邮箱

PATCH /emails/:id 联合验证 warmup_start_time 和 warmup_end_time:结束时间必须晚于同一天的开始时间。仅更新一端时,会使用另一端已保存的时间;无效组合返回 400。无关字段的更新不会重写已有的无效时段。参见 预热时段。

方法路径API 权限
GET/emailsREAD_EMAILS
GET/emails/:idREAD_EMAILS
PATCH/emails/:idWRITE_EMAILS
PATCH/emails/tagsWRITE_EMAILS
GET/emails/allowanceREAD_EMAILS
GET/emails/:id/trackREAD_EMAILS
PATCH/emails/:id/trackWRITE_EMAILS
POST/emails/:id/track/verifyWRITE_EMAILS
PATCH/emails/:id/direct-trackingWRITE_EMAILS
GET/emails/:id/syncREAD_EMAILS
PUT/emails/:id/syncWRITE_EMAILS
GET/emails/:id/identityREAD_EMAILS
POST/emails/:id/identity/refreshWRITE_EMAILS
GET/emails/:id/auth-checkREAD_EMAILS
POST/emails/:id/auth-checkWRITE_EMAILS
GET/emails/:id/behaviorREAD_EMAILS
PUT/emails/:id/behaviorWRITE_EMAILS
GET/emails/:id/behavior/planREAD_EMAILS
POST/emails/:id/holdWRITE_EMAILS
POST/emails/:id/releaseWRITE_EMAILS
DELETE/emails/:idWRITE_EMAILS
POST/emails/:id/sendSEND_CAMPAIGNS

营销活动与邮件序列

对于会话调用者,营销活动、步骤和活动日志限定在所选组织内;对于 API 密钥调用者,则限定在密钥所属组织内。访问取决于下方权限,与活动由谁创建无关。更新和删除步骤还要求步骤属于 URL 中的营销活动。营销活动分析(包括每日、每小时和对比端点)采用相同组织边界,并要求 READ_ANALYTICS(会话调用者则需 查看分析)。

方法路径API 权限
GET/campaignsREAD_CAMPAIGNS
GET/campaigns-overviewREAD_CAMPAIGNS
POST/campaigns-estimateREAD_CAMPAIGNS
POST/campaignsWRITE_CAMPAIGNS
GET/campaigns/:idREAD_CAMPAIGNS
PATCH/campaigns/:idWRITE_CAMPAIGNS
DELETE/campaigns/:idWRITE_CAMPAIGNS
POST/campaigns/:id/duplicateWRITE_CAMPAIGNS
GET/campaigns/:id/attachmentsREAD_CAMPAIGNS
POST/campaigns/:id/attachmentsWRITE_CAMPAIGNS
DELETE/campaigns/:id/attachments/:attachmentIdWRITE_CAMPAIGNS
GET/campaigns/:id/segmentsREAD_CAMPAIGNS
PUT/campaigns/:id/segmentsWRITE_CAMPAIGNS
GET/campaigns/:id/advancedREAD_CAMPAIGNS
PATCH/campaigns/:id/advancedWRITE_CAMPAIGNS
GET/campaigns/:id/ab-variantsREAD_CAMPAIGNS
POST/campaigns/:id/ab-variantsWRITE_CAMPAIGNS
PATCH/campaigns/:id/ab-variants/:variantIdWRITE_CAMPAIGNS
DELETE/campaigns/:id/ab-variants/:variantIdWRITE_CAMPAIGNS
GET/campaigns/:id/ab-analysisREAD_ANALYTICS
POST/campaigns/:id/preflightSEND_CAMPAIGNS
POST/campaigns/:id/test-emailSEND_CAMPAIGNS
POST/campaigns/:id/startSEND_CAMPAIGNS
POST/campaigns/:id/stopSEND_CAMPAIGNS
GET/campaigns/:id/placement-monitorREAD_CAMPAIGNS
PUT/campaigns/:id/placement-monitorSEND_CAMPAIGNS
DELETE/campaigns/:id/placement-monitorSEND_CAMPAIGNS
GET/campaigns/:id/leads/:contactId/holdREAD_CAMPAIGNS
POST/campaigns/:id/leads/:contactId/pauseWRITE_CAMPAIGNS
POST/campaigns/:id/leads/:contactId/resumeWRITE_CAMPAIGNS
GET/campaigns/:id/leads/:contactId/ccREAD_CAMPAIGNS + READ_CONTACTS
PUT/campaigns/:id/leads/:contactId/ccWRITE_CAMPAIGNS + READ_CONTACTS
GET/campaigns/:id/leads/:contactId/cc/suggestionsREAD_CAMPAIGNS + READ_CONTACTS
GET/campaigns/:id/logsREAD_CAMPAIGNS
GET/campaigns/:id/send-planREAD_CAMPAIGNS
GET/campaigns/:id/formsREAD_CAMPAIGNS
GET/POST/PATCH/DELETE/campaigns/:id/steps[/:sid]GET 需要 READ_CAMPAIGNS,其他方法需要 WRITE_CAMPAIGNS
PATCH/campaigns/:id/step-layoutWRITE_CAMPAIGNS
POST/generation/writeWRITE_CAMPAIGNS
POST/generation/editWRITE_CAMPAIGNS
POST/generation/ai-variableWRITE_CAMPAIGNS
GET/email-imagesREAD_CAMPAIGNS
POST/email-imagesWRITE_CAMPAIGNS
DELETE/email-images/:idWRITE_CAMPAIGNS

/campaigns/:id/leads/:contactId/ 下的 hold、pause 和 resume 调用控制某个联系人在单个营销活动中的流程暂停:外出自动回复会自动写入暂停,成员也可手动写入。联系人保持订阅状态并继续作为潜在客户,因此这既不是退订,也不是禁止发送。两项写入操作均声明完整暂停状态,而非增量更改;替换有效暂停时保留原始开始时间,因此重试会作用于同一记录,两者均不需要 Idempotency-Key。参见 暂停潜在客户。

同一路径下的 cc 调用设置每封发给某位潜在客户的邮件都会抄送的联系人。响应携带联系人姓名和地址,因此除营销活动权限范围外,还需要联系人读取权限。PUT 发送完整列表,因此重试会得到相同状态,无需 Idempotency-Key。参见 设置潜在客户的抄送地址。

GET /campaigns/:id/forms 报告此营销活动链接到的表单,以及收件人对表单的操作:发出的个性化链接、谁打开了链接、谁开始填写、谁已提交。参见 表单指南。

GET /campaigns/:id/send-plan 返回今天的发送计划:营销活动预计发送多少封邮件,以及决定数量的每项限制。活跃营销活动的计划在后台计算,并从已保存的快照返回,因此无论活动规模多大,读取都保持快速。computed_at 是遍历计算该快照的时间;若此后活动被编辑、启动、停止,或已进入新的额度日期,且正在计算新计划,则 stale 为 true:当前数字是最近一次有效结果,最新计划会很快跟上。尚无快照的活动(新创建的活动)则在请求时计算。参见 发送计划指南。

/email-images 是工作区用于邮件正文的图片库。POST 接受 multipart file 字段(PNG、JPG、GIF 或 WebP,最大 5 MB),并返回记录及可放入 <img src> 的公开 url;这些文件大小与营销活动附件共用同一存储配额。GET 采用键集分页,最新在前(?limit= 为 1 至 100,?cursor= 为不透明的 pagination.next_cursor)。DELETE 先删除存储对象,再删除记录;若存储拒绝删除,则返回 503,因此失败调用不会改变任何内容,可安全重试;删除成功后,已发送邮件中的该图片将无法加载。

联系人

方法路径API 权限
POST/contacts/searchREAD_CONTACTS
GET/contacts/custom-fieldsREAD_CONTACTS
GET/contacts/lookupREAD_CONTACTS(提供 thread_id 时还需 READ_UNIBOX)
POST/contactsWRITE_CONTACTS
DELETE/contactsBULK_CONTACTS
PATCH/contactsBULK_CONTACTS
GET/contacts/verificationREAD_CONTACTS
POST/contacts/verificationBULK_CONTACTS
GET/contacts/:idREAD_CONTACTS
PATCH/contacts/:idWRITE_CONTACTS
DELETE/contacts/:idWRITE_CONTACTS
GET/contacts/:id/emailsREAD_CONTACTS
GET/contacts/:id/timelineREAD_CONTACTS
GET/contacts/:id/campaignsREAD_CONTACTS
GET/contacts/:id/segmentsREAD_CONTACTS
POST/contacts/exportREAD_CONTACTS
POST/contacts/import/previewWRITE_CONTACTS
POST/contacts/import/commitBULK_CONTACTS
POST/contacts/importsWRITE_CONTACTS
GET/contacts/importsREAD_CONTACTS
GET/contacts/imports/:idREAD_CONTACTS
PATCH/contacts/imports/:idWRITE_CONTACTS
POST/contacts/imports/:id/analyzeWRITE_CONTACTS
POST/contacts/imports/:id/startBULK_CONTACTS
POST/contacts/imports/:id/cancelBULK_CONTACTS
GET/contacts/imports/:id/failed.csvREAD_CONTACTS
GET/contacts/:id/notesREAD_CONTACTS
POST/contacts/:id/notesWRITE_CONTACTS
PATCH/contacts/:id/notes/:noteIdWRITE_CONTACTS
DELETE/contacts/:id/notes/:noteIdWRITE_CONTACTS
GET/contacts/:id/activitiesREAD_CONTACTS
GET/contacts/:id/dealsREAD_CRM
POST/contacts/:id/researchAI_RESEARCH
GET/contacts/:id/researchAI_RESEARCH
POST/contacts/research/batchAI_RESEARCH

GET /contacts/custom-fields 列出联系人中使用的不同自定义字段键(按频率排序),用于构建个性化字段选择器和导入列映射器。在 data 下返回扁平字符串数组,最多 200 个键。

导入由针对同一文件的两个步骤组成:预览解析文件并建议列映射(将标题匹配到现有自定义字段),提交则应用您选定的映射。提交需要更严格的 BULK_CONTACTS 权限范围,因为一次调用最多写入 50,000 行。映射问题、不可用的自定义字段名称或缺少 email 列,均使整个请求返回 400;参见 联系人。

AI 联系人调研消耗积分(每次运行 2 积分,即使没有发现结果也计费),且仅保存有引用依据的发现。参见 AI 联系人调研 指南。批量端点最多接受 500 个联系人 ID,并在后台逐步处理。

联系人分群

方法路径API 权限
GET/segmentsREAD_CONTACTS
GET/segments/fieldsREAD_CONTACTS
POST/segments/previewREAD_CONTACTS
POST/segmentsWRITE_CONTACTS
GET/segments/:idREAD_CONTACTS
PATCH/segments/:idWRITE_CONTACTS
DELETE/segments/:idWRITE_CONTACTS
POST/segments/:id/membersWRITE_CONTACTS
POST/segments/:id/members/lookupREAD_CONTACTS
GET/segments/:id/overridesREAD_CONTACTS
POST/segments/:id/add-to-campaignWRITE_CAMPAIGNS

分群是保存的联系人受众:由条件列表和逐联系人的手动覆盖组成,实时求值。分群由联系人权限范围覆盖,因为它本质上是联系人的一种视图;将分群加入营销活动会写入潜在客户,因此需要营销活动写入权限范围,管理营销活动关联分群(上方的 /campaigns/:id/segments)也同样如此。POST /contacts/search 和 POST /contacts/export 接受 segment_ids,可将任何联系人查询限定到分群。条件格式参见 联系人。

表单

方法路径API 权限
GET/formsREAD_CONTACTS
GET/forms/configREAD_CONTACTS
POST/formsWRITE_CONTACTS
GET/forms/:idREAD_CONTACTS
PATCH/forms/:idWRITE_CONTACTS
DELETE/forms/:idWRITE_CONTACTS
GET/forms/:id/submissionsREAD_CONTACTS
DELETE/forms/:id/submissions/:sidWRITE_CONTACTS
GET/forms/:id/statsREAD_CONTACTS
GET/forms/domainREAD_CONTACTS
PUT/forms/domainWRITE_CONTACTS
POST/forms/domain/verifyWRITE_CONTACTS
GET/forms/:id/links/:contactIDWRITE_CONTACTS
POST/forms/:id/assets/:kindWRITE_CONTACTS
DELETE/forms/:id/assets/:kindWRITE_CONTACTS

托管的潜在客户收集表单;参见 表单指南。表单用于创建联系人,因此由联系人权限范围覆盖。生成个性化链接是在 upsert 之上的 GET 操作,因此重试始终返回相同令牌。/forms/domain 路由管理工作区全局自定义表单域名,JWT 调用者还需 manage_settings 组织权限;PUT 在保存时解析记录,构建 URL 时仅使用已验证的域名。公开页面(/f/:public_id)、其提交端点和嵌入加载器(/forms.js)由独立表单服务在自己的主机(FORMS_DOMAIN)上提供,而非 API 源站,且无需身份验证;不可猜测的公开 ID 即为访问凭据,JSON 端点还要求页面外壳携带的渲染令牌。

潜在客户同步

保存的 Google Sheets 数据源,可按需对联系人执行 upsert。由于同步最终会写入联系人,因此受联系人写入权限范围控制。没有定时同步:仅调用 /lead-sync/sources/:id/sync 时才运行数据源。

方法路径API 权限
GET/lead-sync/google/connectionWRITE_CONTACTS
POST/lead-sync/google/spreadsheetWRITE_CONTACTS
POST/lead-sync/google/previewWRITE_CONTACTS
GET/lead-sync/sources, /lead-sync/sources/:idWRITE_CONTACTS
POST/lead-sync/sourcesWRITE_CONTACTS
PATCH/lead-sync/sources/:idWRITE_CONTACTS
DELETE/lead-sync/sources/:idWRITE_CONTACTS
POST/lead-sync/sources/:id/syncWRITE_CONTACTS

数据源的 column_mapping 在写入数据源时验证,而不是等到下次同步,因此缺少 email 列或自定义字段名称不可用的映射,会在创建或更新时返回 400。参见 集成。

统一收件箱

方法路径API 权限
GET/uniboxREAD_UNIBOX
GET/unibox/countREAD_UNIBOX
GET/unibox/threadREAD_UNIBOX
GET/unibox/:idREAD_UNIBOX
PATCH/unibox/seenWRITE_UNIBOX
PATCH/unibox/folderWRITE_UNIBOX
POST/unibox/replyWRITE_UNIBOX(提供 forward_message_id 时还需 READ_UNIBOX)
POST/unibox/reply/draftREAD_UNIBOX
GET/unibox/compose/candidatesREAD_UNIBOX
POST/unibox/composeWRITE_UNIBOX
POST/unibox/compose/draftREAD_UNIBOX
GET/unibox/draftsREAD_UNIBOX
PUT/unibox/drafts/:idWRITE_UNIBOX
DELETE/unibox/drafts/:idWRITE_UNIBOX
GET/unibox/agent-draftsREAD_UNIBOX
POST/unibox/agent-drafts/:id/approveWRITE_UNIBOX
POST/unibox/agent-drafts/:id/discardWRITE_UNIBOX

PATCH /unibox/folder 将邮件移到 inbox、archive 或 trash。通过 email_ids 指定邮件,通过 thread_ids 指定会话,也可同时指定,两者各最多 500 项。有会话 ID 时优先使用 thread_ids:只移动会话中的部分邮件,会让该会话继续显示,因为只要任一邮件仍位于某处,会话就会显示在那里。随后,移动操作会传递到启用了 relay_folder_moves(默认启用)的每个邮箱:在响应返回后尽力将服务商副本归档、移到垃圾箱或放回收件箱;下一次同步不会撤销任一侧的整理操作,因为服务商端位置独立跟踪,只有服务商自身移动邮件时才跟随。sent、drafts 和 spam 是由服务商决定的投递位置,不是用户手动归档邮件的目标,因此以 400 拒绝。参见 整理会话。

PATCH /unibox/seen 接受相同的两种形式:email_ids 指定单封邮件,thread_ids 指定整个会话。folder 则批量处理一个文件夹,不能与前两者组合。按会话标记未读时,仅标记最新收到的邮件(优先选择不在垃圾邮件和垃圾箱中的邮件);若没有收到的邮件,则标记最新发件副本;其他情况下发件副本保持已读。草稿永不标记为未读。显式 email_ids 和 folder 批量操作也不会将发件或草稿副本标记为未读。

GET /unibox 默认列出所有工作文件夹,排除垃圾邮件、垃圾箱和归档,因此整理后的会话会从所有视图移出,而不仅是收件箱文件夹。传入 include_archived=true 可采用“所有邮件”行为,或传入 folder=archive 直接读取归档文件夹。

POST /unibox/snooze 接受 thread_id 指定一个会话,或 thread_ids 指定最多 500 个。单个形式仍返回稍后处理记录;批量形式返回 data。DELETE /unibox/snooze?thread_id= 接受逗号分隔列表。

带有 forward_message_id 的 POST /unibox/reply 会转发已存储的邮件,涉及披露邮件内容,因此密钥还需 READ_UNIBOX;若密钥限定了邮箱范围,还必须允许访问原邮件所属邮箱。参见 转发邮件。

POST /unibox/reply/draft 根据会话、联系人和您的 写作风格档案 返回 AI 回复草稿(绝不发送)。消耗 AI 积分;参见 AI 积分。

POST /unibox/compose/draft 为新邮件返回有依据的 AI 草稿(绝不发送):收件人联系人记录、往来历史和工作区写作风格档案会作为提示词的上下文,响应包含 text 或用于澄清的 question,并附上 grounding 报告。与回复草稿一样消耗 AI 积分;参见 AI 积分。

POST /unibox/compose 发送全新的外发邮件(非回复)。body_html 按原样发送;body_plain 留空时,根据它生成纯文本部分,POST /unibox/reply 也采用同样行为。省略 email_account_id(或传入 "auto")时,后端为第一位收件人选择最合适的邮箱;响应报告 account_id、account_email、auto 和 picked_reason。位于工作区禁止发送名单上的收件人会在任务入队前以 400 拒绝。GET /unibox/compose/candidates?to=<address> 返回针对该收件人评分的所有活跃邮箱(依据会话历史、剩余每日额度、域名身份验证健康状况),以及解析到的联系人和禁止发送状态;参见 撰写邮件。

/unibox/drafts 端点保存自动保存的撰写草稿,作用域为组织内的调用用户。草稿 ID 由客户端生成,因此 PUT 具有幂等性(适合防抖自动保存和重试);删除不存在的草稿不作任何操作。草稿携带 body(纯文本)和 body_html(纯文本草稿中为空);各自最多 100,000 个字符。

GET /emails/:id/auth-check 对邮箱发件域名实时执行 SPF/DKIM/DMARC 查询并报告结果,不更改任何内容。POST /emails/:id/auth-check 执行相同查询,并为该域名下的所有活跃邮箱记录结论;DNS 修复后正是此操作解除发送限制,因此需要 WRITE_EMAILS 而非 READ_EMAILS。写入无需 Idempotency-Key:结果完全来自公开 DNS,没有请求体,重复执行会收敛到相同结果。参见 域名身份验证。

GET /emails/:id/track 报告邮箱已保存的跟踪域名,以及此部署预期的 CNAME 值(cname_target,取自其 TRACKING_DOMAIN),不执行 DNS 查询。PATCH /emails/:id/track 设置域名并解析一次;POST /emails/:id/track/verify 重新解析已保存域名并记录结论,使已完成传播的记录开始生效。两项写入均基于公开 DNS,且无请求体,因此无需 Idempotency-Key。发送时仅使用已验证域名;在此之前,打开和点击经过共用跟踪主机。参见 自定义跟踪域名。

POST /emails/:id/hold 阻止邮箱发送营销活动邮件,直到 POST /emails/:id/release 将其恢复;预热不受影响,自动休息逻辑也不会解除手动暂停。release 还是邮箱自动进入 resting 后的手动退出方式。两项操作均无请求体且具有幂等性,因此无需 Idempotency-Key。参见 手动暂停邮箱。

GET /emails/allowance 报告工作区当前邮箱数量(used)、允许持有的数量(allowance,无限制时为 null)、remaining,以及该数量的 basis:fair_use(套餐每日发送量除以 sends_per_mailbox)、plan、override(已获批申请)、free 或 unlimited。pending_request 是尚在处理的邮箱增额申请(若有)。remaining 为 0 后,所有连接途径均以 mailbox_allowance_reached 拒绝。参见 邮箱数量额度。

GET /emails/:id/identity 报告邮箱服务商允许使用哪些发件地址、当前使用哪个地址,以及签名是导入的还是在此处编写的;不会联系服务商。POST /emails/:id/identity/refresh 从服务商重新读取该列表并保存;提供 import_signature 时,还会用服务商配置的签名替换已保存签名。系统依据已保存列表验证 send_as_email 选择,因此刷新需要 WRITE_EMAILS 而非 READ_EMAILS;无需 Idempotency-Key,因为它精确写入服务商当前提供的信息。仅限 Gmail。参见 发件身份。

GET /emails/:id/sync 除导入状态和额度外,还报告 skip_folders(邮箱同步忽略的文件夹)及 folders(工作节点上次从服务器列出的文件夹,每项包含 name 及其归属的标准 folder,INBOX 在前;Gmail 和 Outlook 为空)。PUT /emails/:id/sync 接受 {"skip_folders": [...]} 并替换列表:使用服务器列出的名称,匹配时忽略大小写,每项涵盖其子文件夹。新设为跳过的文件夹中已存储邮件会被移除,邮箱会重新发送给工作节点,使变更在下一轮处理时生效,响应返回保存后的列表。INBOX 以及任何已发送、草稿、垃圾邮件、垃圾箱或归档文件夹均以 400 invalid_sync_folder 拒绝;名称超过 50 个或邮箱不是 IMAP 时也同样拒绝。请求体描述目标状态,因此无需 Idempotency-Key。参见 不希望同步的文件夹。

对于 SMTP/IMAP 邮箱,PATCH /emails/:id 接受 save_to_sent(boolean):为 true(默认值)时,工作节点会将每封外发邮件的副本保存到邮箱的“已发送”文件夹。对 Gmail 和 Outlook 邮箱无效,因为其 API 会自行保存副本。参见 保留已发送邮件副本。

对于所有服务商,PATCH /emails/:id 还接受 relay_folder_moves(boolean,默认为 true):为 true 时,通过 PATCH /unibox/folder 整理会话也会在邮箱中移动会话。参见 在邮箱中整理邮件。

同一个需要 WRITE_EMAILS 的邮箱 PATCH 接受 test_mode(diagnostic、off、legacy)、独立的 test_send_enabled/test_receive_enabled、正数 shared_daily_limit/rolling_recipient_limit,以及 send_recovery_resolution。修复解除绑定 held_task_id/held_reason,并要求满足以下之一:authentication_repaired,附带同一邮箱中时间更新、明确成功的外发 evidence_task_id;或 operator_provider_confirmation,附带同一邮箱中已明确应用结果的 evidence_task_id 和非空 confirmation_reference。仅有新的收件箱同步不能作为证据。对于 held_reason: "unknown",显式服务商确认接受 operator_confirmed_sent(要求 message_id,可选 provider_msg_id/thread_id)或 operator_confirmed_not_sent(不含邮件/会话句柄),同时要求非空 confirmation_reference 且不得提供 evidence_task_id。这会将经过审计的正常发送结果加入队列,而不是立即重置暂停。消费者进程先对账处理,再重新开放发送准入;其他结果未知的任务仍保持暂停。超时或缺少已发送副本绝不允许自动重试。现有参与状态为 NULL 的邮箱保持旧版行为;新邮箱默认关闭。参见 发送安全及精确解除要求。

DELETE /emails/:id 先在 Warmbly Cloud 释放邮箱,再删除本地邮箱。已加入预热池的邮箱所保存的凭据会从池中移除;云端托管镜像的认领状态会被释放,使邮箱返回云端工作区并可再次接管。若云端无法确认释放,删除返回 409 mailbox_cloud_unenroll_failed 并保留邮箱记录,以便安全重试。Warmbly 会立即尝试将邮箱恢复到工作节点;若失败,工作节点协调器可能在之后恢复。参见 邮箱。

GET /unibox 和 GET /unibox/thread 返回邮件预览:每行携带 snippet,即单行摘要,而非邮件正文。通过 GET /unibox/:id 读取完整邮件,它返回 body_plain 及 body_html。HTML 在离开 API 前已清理(移除脚本、事件处理程序、嵌入框架及不安全 URL 协议),因此可安全渲染;链接带有 target="_blank" 和 rel="noopener"。此显示副本也会移除 Warmbly 打开跟踪像素,包括引用历史中的像素,因此渲染不会记录营销活动打开。存储和实际投递的副本仍保留像素。少数无法读取已存储正文的邮件,其 body_truncated 为 true,此时 body_plain 回退到摘要。同一响应还包含完整邮件信封信息(from、to、cc、bcc、ReplyTo、date、internal_date、message_id、in_reply_to、size)、所属邮箱(email_id)及其标准 folder。

GET /unibox 还接受 address=<value>(匹配发件人或收件人,用于查询“与此人的所有会话”)及 direction=sent|received(根据您自己的邮箱地址确定方向)。

agent-drafts 端点为 收件箱智能体 提供支持:智能体针对收到的真人回复起草建议回复,并保存在此处供审核。GET 列出待审核草稿;approve 经正常回复流程发送一份草稿(可提供编辑后的 body),并可使用 Idempotency-Key 安全重试;discard 则将其丢弃。只有批准操作会发送邮件。

模板与 CRM

方法路径API 权限
GET/templates, /templates/:idREAD_TEMPLATES
POST/templates/scoreREAD_TEMPLATES
POST/templates/analyzeWRITE_TEMPLATES(会消耗 AI 积分)
POST/PATCH/DELETE/templates[/:id]WRITE_TEMPLATES
GET/crm/pipelines, /crm/pipelines/:idREAD_CRM
POST/PATCH/DELETE/crm/pipelines[/:id][/stages[/:stageId]]WRITE_CRM
GET/crm/deals, /crm/deals/:idREAD_CRM
POST/PATCH/DELETE/crm/deals[/:id]WRITE_CRM
GET/crm/tasks, /crm/tasks/:idREAD_CRM
POST/PATCH/DELETE/crm/tasks[/:id]WRITE_CRM
PATCH/DELETE/crm/tasks(批量,针对 ID 列表或完整筛选结果)WRITE_CRM
GET/crm/task-typesREAD_CRM
POST/PATCH/DELETE/crm/task-types[/:id]WRITE_CRM
GET/crm/settings, /crm/metadata, /crm/owners, /crm/syncREAD_CRM
PUT/crm/settingsINTEGRATIONS
PUT/crm/owners/:externalIdINTEGRATIONS
POST/crm/sync, /crm/sync/retry, /crm/sync/discardINTEGRATIONS
GET/POST/crm/backfillINTEGRATIONS
GET/crm/contacts/:idREAD_CRM
POST/crm/contacts/:id/refreshREAD_CRM
POST/crm/contacts/:id/linkWRITE_CRM
PATCH/crm/contacts/:idWRITE_CRM
GET/crm/listsREAD_CRM
POST/crm/lists/preview, /crm/lists/importWRITE_CONTACTS

从 /crm/settings 到 /crm/lists 的路由用于 CRM 服务商模式(HubSpot 或 Pipedrive),操作工作区实际使用的 CRM。对于控制台会话,读取需要 view_contacts,编辑联系人的 CRM 记录或导入名单需要 manage_contacts,更改模式、匹配负责人、运行同步或复制记录需要 manage_settings。POST /crm/sync/retry、POST /crm/sync/discard 和 POST /crm/backfill 天然可安全重试:重新入队的任务不会重复排队,已复制记录不会再次复制。工作区使用 HubSpot 或 Pipedrive 作为 CRM 时,对销售管道、阶段和任务类型的写入返回 409 crm_managed_externally。参见 CRM。

分析与审计

方法路径API 权限
GET/analytics/*(dashboard、direct、inbox-tagging、deliverability、warmup、warmup/placement、campaigns、accounts、usage)READ_ANALYTICS
GET/audit-logsREAD_AUDIT_LOGS

分析读取对 JWT 调用者使用所选工作区,对 API 密钥调用者使用密钥所属工作区。预热及用量总数也遵循此规则,因此无论哪位成员连接邮箱或创建活动,团队成员看到的都是同一工作区历史。

GET /analytics/warmup 和 GET /analytics/warmup/placement 除本地预热历史外,还包含已关联自托管实例中已加入云端预热池邮箱的详细 Cloud 预热报告。可选 email_id 始终是本地邮箱 ID;工作区报告仅请求该工作区已加入预热池的邮箱。Cloud 失败以错误返回,而非空报告或部分报告。每日预热统计包含 active,表示该日期是否有预热计划,因此合并来源时,每个活跃 UTC 日期只计数一次。

Cloud 提供 POST /pool-link/instance/analytics/warmup 和 POST /pool-link/instance/analytics/warmup/placement,仅供实例令牌使用,不接受 API 密钥。两者均接受 { "remote_ids": ["uuid"], "from": "YYYY-MM-DD", "to": "YYYY-MM-DD" },包含 1 至 100 个已加入预热池的远端 ID,以及最多 366 个 UTC 日期(含首尾)。范围或批量大小无效时返回 400;任一 ID 未由调用实例加入时,整个请求以 pool_link_mailbox_not_found 拒绝。第一个端点返回每日计数,包括 active;第二个返回带有实例侧远端 ID 的原始 daily、hosts、sent、unconfirmed 和 windows 计数。每日投递位置包含计算滚动比例所需的 from 之前回溯数据;托管服务商和发送计数覆盖请求范围,窗口数据则覆盖当前向前回溯的时间窗口。

GET /analytics/inbox-tagging 接受 limit、不透明的 cursor 及 needs_review 查询参数,返回 data、汇总 summary 和 pagination。每行携带 actions,列出该判定被允许执行的操作(hold、stop、task、suppress),summary.acted 统计实际执行过操作的行数。return_date(YYYY-MM-DD 或 null)是要求模型确认的外出返回日期,模型答案位于 answers.return_date。游标、条数或布尔值无效时返回 400。

GET /analytics/accounts 以标准 data 加 pagination 分页结构返回账户健康和用量,使用不透明 cursor。传入 email_ids(逗号分隔,最多 200 个)可仅请求当前页面显示的邮箱;或使用 limit(1–1000,默认 1000)和 cursor 遍历完整邮箱清单。每页中的单邮箱读取按批处理,因此单页开销不会随总邮箱数量增长;工作区邮箱超过一页时,可通过 next_cursor 访问剩余邮箱,而不会被静默丢弃。游标、条数或 ID 无效时返回 400。

收件箱投递位置测试

投递位置测试 会通过工作区某个邮箱实际发送邮件,因此启动和取消测试与启动营销活动需要相同权限,而读取结果属于分析读取。这里所有资源均限定在工作区内:发送前会分别检查测试、发件邮箱、营销活动、步骤和联系人是否属于该工作区。

方法路径API 权限
GET/placement/overviewREAD_ANALYTICS
GET/placement/testsREAD_ANALYTICS
GET/placement/tests/:idREAD_ANALYTICS
POST/placement/testsSEND_CAMPAIGNS
POST/placement/tests/:id/cancelSEND_CAMPAIGNS
GET/placement/seedsREAD_EMAILS
PUT/placement/seeds/:email_account_idWRITE_EMAILS
GET/placement/batchesREAD_ANALYTICS
GET/placement/batches/:idREAD_ANALYTICS
GET/placement/batches/:id/sendersREAD_ANALYTICS
POST/placement/batches/previewSEND_CAMPAIGNS
POST/placement/batchesSEND_CAMPAIGNS
POST/placement/batches/:id/cancelSEND_CAMPAIGNS
GET/placement/coverageREAD_ANALYTICS

对于会话调用者,对应组织权限如下:读取(测试、批次、批次发件邮箱和覆盖情况)需要 查看分析,启动、预览和取消测试或批次需要 发送营销活动,列出种子收件箱需要 查看营销活动,标记种子收件箱需要 管理邮箱。营销活动的投递位置监控(/campaigns/:id/placement-monitor,列于上方营销活动部分)读取需要 查看营销活动,更改需要 发送营销活动。

限定了邮箱范围的密钥只能通过其中一个邮箱启动测试,也只能查看这些邮箱或将其标记为种子邮箱。POST /placement/tests 接受 Idempotency-Key;PUT /placement/seeds/:email_account_id 和 PUT /campaigns/:id/placement-monitor 声明绝对值,因此重试会得到相同状态。GET /placement/tests 接受 limit(1 至 100,默认 25)、不透明 cursor 及可选 campaign_id,返回 data 加 pagination;游标或条数无效时返回 400。列表排除由批次启动的测试,这些测试应通过所属批次读取。

投递位置测试批次 从多个邮箱运行相同测试。POST /placement/batches 接受单次测试所需的邮件内容、种子邮箱组、跟踪和节奏设置,另须在 sender_account_ids 或 sender_scope 中二选一({"type": "campaign", "campaign_id": ...} 或 {"type": "workspace"},可附带 providers、domains、tag_ids、include_inactive 和 untested_days),以及可选 sample、on_unavailable(defer 或 skip)和整个批次的 max_credits。发件邮箱记录写入后,立即以 201 返回状态为 queued 的批次;后端每次启动少量邮箱。POST /placement/batches/preview 接受相同请求体,返回预计计数(发件邮箱、测试、最大发送副本数、免费及付费测试、积分),不启动任何内容也不写入记录。限定了邮箱范围的密钥只能在 sender_account_ids 中指定允许的邮箱(其他邮箱返回 403),服务端范围也仅解析到这些邮箱。POST /placement/batches 接受 Idempotency-Key;取消操作声明终止状态,因此重试返回 placement_batch_not_running 且不作更改。GET /placement/batches 和 GET /placement/batches/:id/senders 与测试列表一样接受 limit 和 cursor;发件邮箱列表还接受 sort(worst,默认值,或 best、email、status)、status 及 q(地址子字符串),任一参数使用未知值均返回 400。参见 投递位置端点参考。

优化顾问

提供有关邮件送达能力、邮箱配置、预热、营销活动效果、邮件内容和名单质量的建议。参见 优化顾问指南。

读取属于对工作区发送状况的分析读取。应用或撤销修复没有独立权限范围:更改通过修复实际使用的工具执行,若调用者缺少该工具权限则被拒绝,因此能读取建议的密钥不能借助建议执行本来无权直接进行的更改。

方法路径API 权限
GET/advisor/recommendationsREAD_ANALYTICS
GET/advisor/summaryREAD_ANALYTICS
GET/advisor/settingsREAD_ANALYTICS
POST/advisor/refreshREAD_ANALYTICS
POST/advisor/recommendations/:id/snoozeREAD_ANALYTICS
POST/advisor/recommendations/:id/dismissREAD_ANALYTICS
POST/advisor/recommendations/:id/feedbackREAD_ANALYTICS
POST/advisor/recommendations/:id/applyREAD_ANALYTICS,以及底层更改所需的权限
POST/advisor/recommendations/:id/undoREAD_ANALYTICS,以及底层更改所需的权限

应用和撤销在密钥自身权限范围内执行修复,限定了邮箱范围的密钥只能对其中的邮箱应用或撤销修复(否则返回 403)。更改 优化顾问设置(PATCH /advisor/settings)与其他组织设置一样仅接受 JWT。关闭整个工作区的检查属于治理行为,任何读取权限范围都不应允许执行。POST /advisor/recommendations/:id/agent-fix 也同样仅接受 JWT,并要求 USE_AI:它以具名成员身份执行并消耗积分,不应有任何 API 权限范围允许密钥无人审核地改写工作区营销活动。

API 密钥自助管理

方法路径API 权限
GET/api-keysAPI_KEYS
POST/api-keysAPI_KEYS,不接受 OAuth 令牌
GET/api-keys/permissionsAPI_KEYS
GET/api-keys/:idAPI_KEYS
PATCH/api-keys/:idAPI_KEYS,不接受 OAuth 令牌
DELETE/api-keys/:idAPI_KEYS,不接受 OAuth 令牌
DELETE/api-keys/:id/permanentAPI_KEYS,不接受 OAuth 令牌
DELETE/api-keys/self无

DELETE /api-keys/:id/permanent 删除已撤销或已过期的密钥,同时删除其使用日志。仍可用于身份验证的密钥返回 409,因为撤销操作负责记录凭据何时、为何终止。参见 撤销与删除密钥。

通过已登录会话调用 POST /api-keys 时,要求近期确认(POST /auth/reauth),因为密钥的有效期可能长于创建它的会话,被盗浏览器令牌不应能够留下长期凭据。API 密钥调用不受影响:它没有会话,也无法提供第二因素;它自身已由确认过的会话签发,并由 API_KEYS 权限范围显式授权管理。因此自动化和 CLI 仍可正常使用。

创建、编辑、撤销和删除密钥仅允许已登录成员或 API 密钥执行;OAuth 应用令牌返回 403 oauth_token_not_allowed。新建或编辑的密钥始终受创建者边界限制:成员不能赋予角色未覆盖的权限,API 密钥也不能赋予调用密钥本身没有的权限、邮箱或 IP 地址(403 api_key_permissions_exceed_caller)。参见 角色可委派的权限。GET /api-keys/permissions 通过 grantable 报告调用者的边界。

DELETE /api-keys/self 撤销本次请求所使用的密钥,是这里唯一不要求权限范围的路由。凭据必须始终能够终止自身:如果退出要求 API_KEYS,用户归还笔记本电脑时,设备上的只读密钥可能仍有效,而 warmbly auth logout 正是为防止这种情况。JWT 调用者会收到 400:该请求中没有可终止的密钥,只有会话,会话通过 POST /auth/logout 结束。

OAuth 应用

注册和管理工作区拥有的 OAuth 应用。流程本身(授权、获取令牌、撤销)列于下方“仅限 JWT”和“公开”部分。此处所有路由,以及 POST /oauth/application-logo,均以 403 oauth_token_not_allowed 拒绝 OAuth 应用令牌。

方法路径API 权限
GET/oauth/applicationsAPI_KEYS
POST/oauth/applicationsAPI_KEYS
GET/oauth/applications/:idAPI_KEYS
PATCH/oauth/applications/:idAPI_KEYS
DELETE/oauth/applications/:idAPI_KEYS
POST/oauth/applications/:id/rotate-secretAPI_KEYS
POST/oauth/applications/:id/logoAPI_KEYS
DELETE/oauth/applications/:id/logoAPI_KEYS
GET/oauth/applications/:id/webhook-secretAPI_KEYS
POST/oauth/applications/:id/webhook-secret/rotateAPI_KEYS
GET/oauth/applications/:id/webhook-endpointsAPI_KEYS
GET/oauth/applications/:id/webhook-deliveriesAPI_KEYS
GET/oauth/applications/:id/listingAPI_KEYS
PUT/oauth/applications/:id/listingAPI_KEYS
DELETE/oauth/applications/:id/listingAPI_KEYS

listing 路由将应用发布到 社区目录。PUT 替换整个目录条目,DELETE 在没有可移除内容时也成功,因此两者均可安全重试。浏览目录使用 GET /integrations/community 和 GET /integrations/community/:slug,位于下方 /integrations/* 部分。

运维操作

方法路径API 权限
GET/PATCH/outreach/settingsWRITE_CAMPAIGNS
POST/deliverability/eventsWRITE_CAMPAIGNS
GET/suppressionsREAD_CONTACTS
POST/suppressionsWRITE_CONTACTS
DELETE/suppressions/:idWRITE_CONTACTS
GET/tasks/dlqSEND_CAMPAIGNS
POST/tasks/dlq/:id/replaySEND_CAMPAIGNS
GET/POST/PATCH/DELETE/webhooks[/:id]WEBHOOKS
POST/webhooks/:id/rotate-secretWEBHOOKS
POST/webhooks/:id/verifyWEBHOOKS
GET/webhooks/event-typesWEBHOOKS
GET/webhooks/deliveriesWEBHOOKS
GET/webhooks/:id/deliveriesWEBHOOKS
POST/webhooks/deliveries/:deliveryId/redeliverWEBHOOKS
GET/webhooks/throttle-dropsWEBHOOKS
GET/POST/DELETE/integrations/*(/integrations/slack/* 除外,它 仅支持 JWT;另排除 /integrations/bookings)INTEGRATIONS
GET/integrations/bookingsREAD_CONTACTS
GET/PUT/integrations/salesforce/:id/settingsINTEGRATIONS
GET/integrations/salesforce/:id/overview, /metadata, /users, /list-views, /campaigns, /activityINTEGRATIONS
POST/integrations/salesforce/:id/import/previewINTEGRATIONS
GET/POST/PATCH/DELETE/integrations/salesforce/:id/import-sources[/:sourceId]INTEGRATIONS
POST/integrations/salesforce/:id/import-sources/:sourceId/runINTEGRATIONS
POST/integrations/salesforce/:id/activity/retry, /sync-nowINTEGRATIONS
GET/contacts/:id/salesforceREAD_CRM
POST/contacts/:id/salesforce/syncINTEGRATIONS
DELETE/contacts/:id/salesforce/links/:linkIdINTEGRATIONS
GET/integrations/apollo/:id, /listsINTEGRATIONS
PUT/integrations/apollo/:id/keyINTEGRATIONS
POST/integrations/apollo/:id/import/previewINTEGRATIONS
GET/POST/PATCH/DELETE/integrations/apollo/:id/import-sources[/:sourceId]INTEGRATIONS
POST/integrations/apollo/:id/import-sources/:sourceId/runINTEGRATIONS
GET/integrations/apollo/:id/enrichments[/:runId]INTEGRATIONS
POST/integrations/apollo/:id/enrichmentsINTEGRATIONS 和 BULK_CONTACTS
GET/PATCH/integrations/clay/:idINTEGRATIONS
GET/POST/PATCH/DELETE/automations[/:id]INTEGRATIONS
PATCH/automations/:id/layoutINTEGRATIONS

已登录成员创建、编辑、启用或删除自动化流程需要 manage_settings,因为流程以工作区身份运行;列出、打开、测试和读取运行历史只需 use_integrations。

启动 Apollo 数据补全会写入联系人,并消耗工作区的 Apollo 积分,因此除 INTEGRATIONS 外还需 BULK_CONTACTS(对于成员,即 use_integrations 和 manage_contacts)。保存密钥、导入配置和 Clay 设置需要 manage_settings;预览和运行导入需要 use_integrations。POST /integrations/inbound/clay/:secret 是 Clay 表格发送行数据的 URL。它不需要 API 密钥,因为路径中的密钥就是凭据。 | GET/POST/PATCH/DELETE | /warmup/routing[/:id] | WARMUP_ROUTING |

重试安全性

更改数据的 API 请求可包含 Idempotency-Key 请求头。Warmbly 按组织和幂等键保存已完成响应 24 小时。对相同方法、路由、查询及请求体复用同一幂等键时,重放原始响应,并带有 X-Idempotent-Replayed: true;将同一键用于不同请求时,返回 409 Conflict。

身份

方法路径API 权限
GET/me(任意已通过身份验证的密钥)

GET /me 返回当前凭据所属身份:user_id、email、name、organization_id、organization_name、auth_type(api_key、oauth 或 jwt)以及授予的 scopes。它不要求特定权限,因此适合用于验证连接并显示可读标签。与 /auth/me(仅限 JWT)不同,API 密钥和 OAuth 令牌均可访问此端点。

标签

文件夹(用于营销活动)、标签(用于邮箱)和分类标签(用于联系人、收件箱会话及表单,通过 /categories 端点管理)是三个结构相同的登记表。它们均属于 工作区,不属于创建者。无论由谁创建,所有成员都看到相同集合,并通过 GET /auth/me 读取,该端点返回会话所选工作区的 folders、tags 和 categories;没有独立列表端点,也没有单独的读取权限范围。更改登记表采用与其所标注记录相同的权限控制,因此需要下表中的 API 权限,或对应 JWT 权限 MANAGE_CAMPAIGNS、MANAGE_EMAILS、MANAGE_CONTACTS。仅有成员身份时为只读。

position 是各自登记表内的顺序,从 0 开始且连续。移动操作返回完整的新顺序。每个登记表最多包含 100 项。

方法路径API 权限
POST/foldersWRITE_CAMPAIGNS
PATCH/folders/:idWRITE_CAMPAIGNS
PATCH/folders/:id/moveWRITE_CAMPAIGNS
DELETE/folders/:idWRITE_CAMPAIGNS
POST/tagsWRITE_EMAILS
PATCH/tags/:idWRITE_EMAILS
PATCH/tags/:id/moveWRITE_EMAILS
DELETE/tags/:idWRITE_EMAILS
POST/categoriesWRITE_CONTACTS
PATCH/categories/:idWRITE_CONTACTS
PATCH/categories/:id/moveWRITE_CONTACTS
DELETE/categories/:idWRITE_CONTACTS

参考数据

方法路径API 权限
GET/plans(任意已通过身份验证的密钥)
GET/timezones(任意已通过身份验证的密钥)

仅支持 JWT

这些端点永远不接受 API 密钥。它们依赖绑定到真人的会话:计费流程、治理、OAuth 接入、WebSocket 初始化及运维销毁操作。

采用 多个控制台共用后端 时,密码重置和邀请邮件、推荐链接及计费返回地址使用发起浏览器所对应的、已明确配置的控制台源地址。没有可信源时,使用主控制台。邮箱、管理员授权、集成和 Slack 身份 OAuth 回调从仍有效的服务端状态恢复目标,绝不使用回调查询参数。已过期或已消费的路由状态不会被转发到其他控制台。

  • POST /auth/login, /auth/login/confirm, /auth/register, /auth/register/confirm, /auth/refresh, /auth/reset-password, /auth/reset-password/confirm
  • POST /auth/reauth(对仍有效的会话重新验证账户持有人,用于需要近期确认的更改)
  • GET /auth/reauth/methods(此账户可用的确认方式:密码、双重验证代码、通行密钥,以及可重新验证的关联登录服务商)
  • POST /auth/reauth/passkey/begin、/auth/reauth/passkey/finish(使用此账户自己的某个通行密钥确认)
  • POST /auth/reauth/sso/begin、/auth/reauth/sso/finish(在浏览器窗口中通过关联到此账户的 Google、Apple 或单点登录身份确认)
  • POST /auth/reauth/native/begin、/auth/reauth/native(使用携带会话 nonce 的原生“通过 Apple 登录”或 Google ID 令牌确认)
  • GET /auth/config(公开部署能力:后端启用了哪些登录方式、之后是否有登录验证码步骤、注册是否开放、实例是否仍待认领)
  • POST /auth/app-attest/challenge、/auth/app-attest/keys(原生应用的 App Attest 质询和一次性密钥注册,采用独立的每 IP 额度 APP_ATTEST_IP_RATE_LIMIT)
  • GET /auth/instance(仅限 JWT:自托管实例当前运行的 Warmbly 版本,以及是否存在更新版本,供控制台版本标记使用;托管部署仅返回 self_hosted: false)

POST /auth/register 接受可选 invite 字段,携带邀请令牌。在采用 DISABLE_REGISTRATION=invite_only 的部署中,此令牌用于许可注册,账户会在发出邀请的组织中创建,而不是新建组织。令牌必须对应有效邀请,且邀请邮箱与提交地址相同,否则请求以 invitation_invalid 拒绝。在关闭注册的部署中省略此字段,会返回 registration_invite_only 或 registration_closed。参见 错误码。

需要近期再次确认身份的操作

以下更改除原有所需权限外,还要求会话在最近五分钟内确认过账户持有人:

操作路由
创建 API 密钥POST /api-keys
在 OAuth 同意页面批准应用POST /oauth/authorize
批准 CLI 登录POST /auth/cli/codes/:code/approve
添加通行密钥POST /auth/passkey/register/begin, /finish
移除通行密钥DELETE /auth/passkey/credentials/:id
启用双重身份验证POST /auth/2fa/enroll/start、/confirm(无密码账户见下方说明)
转移工作区POST /organization/transfer-ownership
邀请成员、更改成员角色或访问范围POST /organization/members/invite, PATCH /organization/members/:id, PUT /organization/members/:id/access
导出或导入整个工作区POST /organization/current/export, POST /organization/current/import
计划删除工作区或账户POST /organization/current/danger-zone/delete, POST /me/danger-zone/delete
批准自托管实例的预热池关联POST /pool-link/codes/:code/approve
查看或轮换签名密钥POST /webhooks/:id/rotate-secret, GET /integrations/connections/:id/webhook-secret, POST /oauth/applications/:id/rotate-secret, GET /oauth/applications/:id/webhook-secret, POST /oauth/applications/:id/webhook-secret/rotate
记录、使用或移除整个域的管理员授权POST /emails/grants/google/finish, POST /emails/grants/microsoft/finish, POST /emails/grants/:id/connect, DELETE /emails/grants/:id
管理面板:签发节点集群加入令牌、授予管理员权限、导出或导入任意工作区POST /admin/fleet/join-token, POST /admin/admins/:userId/grant, POST /admin/organizations/:id/exports, POST /admin/organizations/:id/imports

这些操作至少涉及以下情况之一:发放有效期长于创建会话的凭据、披露密钥、更改谁可访问、被操作对象本人无法撤销,或访问整个域的邮件。未经确认时返回 403,错误码为 reauth_required;请确认后重试。参见 错误码。

GET /auth/reauth/methods 返回账户可用的确认方式,客户端应只提供这些方式:

{
  "password": false,
  "totp": false,
  "passkey": true,
  "providers": [{ "id": "google", "label": "Google" }],
  "native_providers": ["google"],
  "valid_for_seconds": 300
}
  • 密码或验证码: 调用 POST /auth/reauth,提供 password,或当前双重验证代码或恢复 code。
  • 通行密钥: POST /auth/reauth/passkey/begin 返回仅限此账户自身通行密钥的 WebAuthn 请求 options;将 options.publicKey 传给浏览器,再将断言以 credential 发送到 POST /auth/reauth/passkey/finish。认证器必须验证用户。
  • 浏览器中的关联身份: 向 POST /auth/reauth/sso/begin 提供 provider(providers[].id 之一),返回 url 和 binding。在窗口中打开 url,并保留 binding。服务商会将该窗口返回控制台的 /reauth/complete,附带一次性 code,只有发起流程的会话可以兑换:调用 POST /auth/reauth/sso/finish,提供 code 和 binding。服务商验证的身份必须已关联到该账户;其他账户以 reauth_identity_mismatch 拒绝,绝不会按邮箱地址匹配。
  • 原生应用: POST /auth/reauth/native/begin 返回 nonce。将其原样用作“通过 Apple 登录”请求的 nonce,或 Google 授权的 nonce,然后将 ID 令牌发送到 POST /auth/reauth/native,并提供 provider(apple 或 google)。nonce 仅可使用一次,并绑定到会话。

各方式成功时均返回 { "valid_for_seconds": 300 },且仅确认发起调用的会话。

此规则适用于会话调用者。API 密钥或 OAuth 令牌没有可供确认的会话,也不是此处针对的威胁,因此直接进入路由的权限检查。

完成登录后的前五分钟视为会话已确认。对于既无密码也未启用双重验证的账户,POST /auth/reauth 返回 400,错误码为 reauth_no_factor;应改用通行密钥或关联身份确认。如果这些方式都没有,则重新登录。

GET /auth/config 新增两个字段:invites_required(boolean,创建账户需要邀请令牌时为 true)及 docs_url(string,部署提供的账户和访问文档链接,供客户端在拒绝消息旁展示)。

GET /auth/config 还携带 websocket_url 和 app_url(均为字符串,实例未配置相应值时各自省略)。它们分别是开发者客户端连接的实时网关,以及客户端将用户引导至的控制台源地址。两者在这里提供,是因为自托管实例的主机布局由运维人员决定,无法通过其他方式发现:CLI 通过读取它们支持 warmbly events tail 和 warmbly browse。

POST /getaway 仅限会话调用,并签发十分钟有效的 WebSocket 票据。其 url 仍为直连网关;可选 proxy_path 相对于 /v1 解析,用于浏览器连接。GET /realtime/socket/websocket 使用该票据升级连接,同时保留已配置实时服务的源检查和连接限制。不接受普通访问令牌、API 密钥或 OAuth 令牌。参见 实时 WebSocket。

此外,api_url 是此 API 自身的公开基础地址(供可复制示例指向正确服务器),brand 表示部署声明的品牌身份:name,以及 website_url、website_label、terms_url、privacy_url、support_email,未设置时分别省略。未配置任何 EMAIL_BRAND_* 的自托管实例仅提供 name;客户端应完全不显示链接,而不是替换成自行选择的链接。参见 配置。

GET /auth/config 还携带 gmail_oauth_connect(boolean):是否允许通过 Google 登录连接新的 Gmail 邮箱。BOX_GOOGLE_CLIENT_ID 和 BOX_GOOGLE_CLIENT_SECRET 均为必需。两者设置后,该能力默认为 true;显式设置 BOX_GOOGLE_OAUTH_CONNECT=false 或无效值会禁用它。为 false 时,应提供应用密码途径(对 Gmail 服务器调用 POST /emails/onboarding/smtp-imap),而不是发起最终返回 mailbox_gmail_oauth_disabled 的 OAuth 流程。控制台还要求部署本地的 前端启用设置 才会显示 Google 登录。无论如何,现有通过 Google 登录连接的邮箱均不受影响。

GET /auth/config 还携带 app_attest(boolean):服务器是否在 POST /auth/login、/auth/register、/auth/reset-password 和 /auth/reset-password/confirm 上接受原生应用的 App Attest 证明,以替代 Turnstile 令牌。结合 captcha 读取:没有验证码要求时,无需发送任何内容;需要验证码且有 app_attest 时,应用发送证明;需要验证码但没有此能力时,应用内无法使用邮箱和密码登录。

GET /auth/config 还携带 billing_enabled(boolean)。部署使用 BILLING_PROVIDER=none(自托管默认值)运行时,它为 false:服务端解锁所有功能,因此控制台将工作区显示为自托管而非免费试用,并隐藏计费及推荐页面。仅有 self_hosted 并不意味着如此,因为自托管安装仍可运行 Stripe。

  • POST /auth/setup(首次运行认领:将启动时输出的一次性令牌兑换为所有者账户。已有任何账户时拒绝)

  • GET /auth/providers、POST /auth/apple、POST /auth/google(原生应用社交登录)

  • POST /auth/oidc/begin、GET /auth/oidc/callback(通用 OpenID Connect 登录)

  • POST /auth/google/begin、GET /auth/google/callback、POST /auth/apple/begin、POST /auth/apple/callback(浏览器中的“通过 Google 登录”和“通过 Apple 登录”)

  • POST /auth/sso/exchange(将上述任一回调的一次性交接代码兑换为会话;POST /auth/oidc/exchange 是同一端点的旧名称)

  • POST /auth/sso/link(完成解析到现有密码账户的服务商登录:接受该账户密码、关联身份并返回会话)

  • POST /auth/logout, POST /auth/logout-all, GET /auth/me, PATCH /auth/me/onboarding

  • PUT /auth/me/product-tour(记录已登录用户已完成或跳过控制台产品导览,返回 product_tour_completed_at,GET /auth/me 也携带此字段。天然可安全重试:重复调用保留首次时间,因此无需 Idempotency-Key)

  • POST /auth/me/avatar, DELETE /auth/me/avatar

  • POST /emails/onboarding/oauth/start、POST /emails/onboarding/oauth/finish、POST /emails/onboarding/smtp-imap。oauth/start 接受可选 login_hint(邮箱地址),在服务商登录中预先选择该邮箱,导入中的 登录 行即通过此方式打开。对于 Google 和 Microsoft 控制台流程(return: "web"),浏览器的 Origin 会与精确配置的控制台源地址核验,并绑定到 OAuth 状态;不可信源返回 400 mailbox_oauth_return_origin。没有 Origin 的请求在状态仍有效时继续路由到主控制台

  • POST /emails/onboarding/smtp-imap/bulk(在 accounts 中最多提供 50 行 SMTP/IMAP 配置;返回 200,每行包含 status,其值为 connected、skipped 或 failed,以及 code。超出工作区 邮箱数量额度 的行会在尝试连接任何凭据之前以 mailbox_allowance_reached 失败。天然可安全重试:已连接邮箱为 skipped,因此无需 Idempotency-Key)

  • /emails/imports 下的 邮箱导入 路由均要求 JWT 权限 MANAGE_EMAILS。它们携带密码,因此与接入流程一样,永不接受 API 密钥:

    • POST /emails/imports/preview:逐行、逐域名预览导入此输入将执行的操作,不实际执行
    • POST /emails/imports:保存各行并在后台连接;以 201 返回导入对象
    • GET /emails/imports:工作区的导入,最新在前
    • GET /emails/imports/:id:单个导入及其计数,失败项按 cause 分组
    • GET /emails/imports/:id/rows:按行号返回导入记录,可按 status(逗号分隔)和 cause 筛选
    • PATCH /emails/imports/:id/rows/:line:修正一个失败行(password、app_password、username、smtp、imap)并重新排队
    • POST /emails/imports/:id/retry:重新排队失败行,可选择全部、某一 cause 的行,或指定 lines;可选提供一个新的 password 应用于全部所选行
    • POST /emails/imports/:id/cancel:停止尚未开始的行;已经连接中的行会继续完成
    • POST /emails/imports/:id/dismiss:在工作区的 GET /emails/imports 中隐藏此导入;若仍在运行,先停止。其行数据和历史保留,GET /emails/imports/:id 仍可读取。返回 204;重复调用不作更改
    • GET /emails/imports/:id/failed.csv:返回所有未连接成功的行,保留上传内容但去除密码,附带 status、problem 和 how_to_fix

    预览和创建接受 multipart/form-data:file(CSV、TSV 或 XLSX,最大 10 MB)或 text(粘贴的列表)、mapping(列索引到字段的 JSON 对象,例如 {"0":"email","1":"password"};省略时自动映射)以及 options(JSON:has_header、shared_password、值为 update 或 skip 的 on_existing、save_mapping,以及应用于每个邮箱的 settings)。一次导入最多 5,000 行。两个列表端点返回 data 及包含 next_cursor、has_more 的 pagination;limit 对导入最多为 100,对行最多为 200;非此 API 签发的游标返回 400 和 invalid_cursor。这些操作均不接受 Idempotency-Key。重复创建会生成第二个导入,其行数据会发现第一次导入的邮箱已连接,继而更新(或跳过),因此不会重复连接。重试仅重新排队失败行,修正操作会拒绝非失败行,因此重复执行两者均不会重复连接。重复取消导入不作操作。进度通过实时事件 MAILBOX_IMPORT_PROGRESS 发布;参见 实时通信。错误码见 邮箱导入拒绝原因

  • /emails/vendors 下的 邮箱供应商 连接要求 JWT 权限 MANAGE_EMAILS。密钥在服务端密封保存,任何响应都不会返回它:

    • GET /emails/vendors/catalog:支持的供应商,以及各自的 fields(key、label、secret、required、help)和 key_help_url
    • GET /emails/vendors:工作区的供应商连接,包含 status、last_error 和邮箱数量
    • POST /emails/vendors:vendor、label 和 fields;先向供应商验证密钥,返回 201。重复调用会创建第二个连接
    • PATCH /emails/vendors/:id:重命名,或在向供应商验证新密钥后替换 fields。可安全重复调用
    • DELETE /emails/vendors/:id:删除保存的密钥;由其导入的邮箱保持连接。重复调用返回 404
    • GET /emails/vendors/:id/mailboxes:供应商账户的邮箱,已存在于工作区的邮箱标记为 connected
    • POST /emails/vendors/:id/import:mailbox_ids 或 all,加上与文件导入相同的 options;以 201 返回导入对象。每次调用创建一个新导入;重复调用会发现前一次的邮箱已连接,继而更新(或跳过)
  • /emails/grants 下的 管理员授权 要求 JWT 权限 MANAGE_EMAILS。记录、使用或移除授权的四个路由还需要 近期身份确认:

    • GET /emails/grants/config:此实例是否接受 Google 和 Microsoft 授权、管理员需授权的 Google google_client_id 和 google_scopes,以及 google_missing 和 microsoft_missing(仍未设置的实例配置名称,该服务商已就绪时为空)
    • GET /emails/grants、GET /emails/grants/:id:授权列表及其 provider、tenant、覆盖的 domains、status 和邮箱数量
    • GET /emails/grants/migration:工作区中采用逐邮箱 Google 登录且可以 选择切换连接方式 的邮箱,按域名分组:data 为列表,各项包含 domain、kind(workspace 表示转为管理员授权,或 personal,即 gmail.com 这样的公共邮箱地址,转为应用密码)、grant_id(工作区有覆盖该域名的有效 Google 授权时)以及 mailboxes(id、email、name、status);total 统计邮箱数。登录凭据由 Warmbly Cloud 持有的邮箱不在列表中。只读
    • POST /emails/grants/google/start:domain 和 admin_email(属于该域名)。返回工作区证明域名控制权的方式:实例有 Google 登录应用时,method 为 signin,附带 Google 登录 url 和 state(有效期 15 分钟);否则 method 为 dns。两者均包含 txt_name(_warmbly.<domain>)和 txt_value(warmbly-verify=...,对工作区和域名唯一),因为 DNS 证明始终可用。可安全重复调用
    • POST /emails/grants/google/finish(近期确认):提供 Google 登录返回的 state 和 code,登录身份必须是该域名的 admin_email 本人;或在发布 TXT 记录后提供 domain 和 admin_email。目录必须将 admin_email 列为超级管理员。返回 201。state 仅可使用一次;重复完成 DNS 验证会重新验证并更新同一授权,每个域名一个授权
    • POST /emails/grants/microsoft/start:供全局管理员使用的管理员同意 url 和 state,有效期 15 分钟
    • POST /emails/grants/microsoft/finish(近期确认):同意回调中的 state 和 code;返回 201。记录的组织是管理员同意授权的组织,以兑换登录结果报告的组织为准。state 仅可使用一次,因此重复调用以 mailbox_grant_state_invalid 拒绝。每个租户一个授权:再次同意会更新同一授权
    • POST /emails/grants/:id/check:立即验证,通过时重新启动该授权下已停止的邮箱。可安全重复调用
    • DELETE /emails/grants/:id(近期确认):移除授权;由其连接的所有邮箱都会停止。重复调用返回 404
    • GET /emails/grants/:id/users:获授权目录,各用户标明 enabled 和 connected,已连接时还包含 email_account_id。若用户邮箱已经通过同一服务商的独立登录连接到此处(Google 或 Microsoft,且非由 Warmbly Cloud 持有),则 upgrade 为 true;连接操作会原地将该邮箱转为使用此授权
    • POST /emails/grants/:id/connect(近期确认):user_ids 或 all(所有已启用但尚未连接的用户,加上所有标记为 upgrade 的用户),以及导入 options;以 201 返回导入对象。每次调用创建一个新导入;重复调用会发现前一次的邮箱已连接,继而更新(或跳过)。若用户邮箱已作为委派邮箱存在,则重新关联到此授权;使用独立登录的邮箱则原地转换为授权方式,保留历史、营销活动和预热,且不额外占用邮箱数量额度
  • /emails/domains 下的 发件域名 要求 JWT 权限 MANAGE_EMAILS。:domain 是不含协议或路径的域名:

    • GET /emails/domains:工作区用于发送的所有域名,包含邮箱数量、邮件托管方、SPF、DKIM 和 DMARC、使用中的跟踪主机及重定向。若已连接的 邮箱供应商 账户持有域名,vendor_domain 包含 vendor、connection_id、当前 forwarding(供应商报告时)、can_forward、can_unforward、forwarding_reviewed(更改由供应商工作人员稍后应用)、can_dns 和 dns_types
    • POST /emails/domains/bulk:domains(1 至 100 个)、tracking_label(单个 DNS 标签,如 link;每个域名获得 <label>.<domain>)和/或 redirect_url,还可提供按域名为键的 tracking_hosts 和 redirect_urls 对象,为所列域名单独指定主机或网站,以替代共用值。供应商 API 支持时,各域名使用供应商途径(写入 CNAME、转发根域名),否则保存并等待 DNS。可选 served_by(instance 或 cloud)指定无供应商转发时由何处提供重定向服务;省略则保留各域名当前选择。返回 data,每个域名一行,包含 tracking(host、值为 vendor 或 dns 的 via、verified、mailboxes、cname_target,以及供应商拒绝记录时的 note)和 redirect(target_url、值为 vendor、dns 或 cloud 的 via、verified、reviewed);遭拒域名的行携带 error 和 code,不会阻止其他域名处理。可安全重试:各设置均为赋值,而非追加
    • GET /emails/domains/:domain/tracking-suggestion:建议使用的跟踪 host、其 status(active、found 或 suggested)、cname_target,以及已连接供应商账户持有该域名时的 vendor_domain
    • PUT /emails/domains/:domain/tracking:为域名下所有邮箱设置 host(为空则清除);返回验证结果及更改的 mailboxes 数量。具有幂等性
    • PUT /emails/domains/:domain/redirect:target_url,可选 include_www(默认 true),以及可选 served_by(instance;或在 已关联 Warmbly Cloud 的自托管实例上使用 cloud;省略时保留当前选择,新重定向由本实例提供服务)。检查一次后返回重定向及其 records、served_by、serve_host(实际响应的跟踪主机,代理将域名路由至此);DNS 验证后还返回 reach:最近一次访问域名的结果,包括 status(ok、not_reaching、https_error 或 unreachable)、hint(not_routed、host_header、wrong_target、certificate、no_listener,或跟踪服务正在加载刚验证重定向时的 settling)、一句 detail、响应方自报身份时的 proxy,以及 checked_at。具有幂等性:重复调用保留相同所有权值,因此 TXT 记录持续有效
    • POST /emails/domains/:domain/redirect/verify:立即检查 DNS 并访问域名;由 Warmbly Cloud 提供服务的重定向,由 Cloud 检查并返回其结论。可安全重复调用
    • DELETE /emails/domains/:domain/redirect:停止提供重定向服务;由 Warmbly Cloud 提供时也会在 Cloud 停止。重复调用返回 404
    • PUT /emails/domains/:domain/vendor-forwarding:url;持有域名的供应商账户将根域名转发至此。can_unforward 为真时,空 url 会移除转发。返回更新后的 vendor_domain。具有幂等性
    • POST /emails/domains/:domain/vendor-tracking:host,必须是该域名的子域名;供应商将其 CNAME 写为本实例的跟踪主机,然后域名下所有邮箱使用此主机。响应与 PUT .../tracking 相同。可安全重试:记录是替换,而非新增

    以上操作均不接受 Idempotency-Key;各自的重试行为已在上方说明。供应商连接、管理员授权和重定向发生更改时,发布 AUDIT_CREATED,其中 entity_type 为 mailbox_vendor、mailbox_grant 或 domain_redirect。错误码见 邮箱来源拒绝原因

  • POST /emails/onboarding/oauth/reauth/:id、PUT /emails/onboarding/smtp-imap/:id(凭据更改后重新连接现有邮箱;JWT 权限 MANAGE_EMAILS)

  • POST /emails/onboarding/app-password/:id(JWT 权限 MANAGE_EMAILS):通过 app_password(16 个字母的 Google 应用密码,忽略空格),将邮箱从逐邮箱 Google 登录转为 Gmail IMAP 和 SMTP。保存任何内容前,会向 Gmail 服务器验证密码,拒绝原因与 SMTP/IMAP 连接相同;成功后邮箱原地变为 smtp_imap,保留已导入邮件、营销活动和预热,并以 200 返回邮箱。对其他邮箱(包括已切换的邮箱)返回 409 mailbox_not_google_signin,因此重复调用不作更改,也无需 Idempotency-Key;值不是 16 个字母时返回 400 app_password_invalid。发布 AUDIT_CREATED,其中 entity_type 为 email_account

  • GET /oauth/authorize/details、POST /oauth/authorize(同意流程:由用户批准第三方应用,授权仅包含成员角色所覆盖的权限范围)。POST /oauth/authorize 与创建 API 密钥一样,要求近期确认(POST /auth/reauth)

  • GET /oauth/authorized-apps、DELETE /oauth/authorized-apps/:id(用户已授权的应用)

  • GET /oauth/workspace-authorizations、DELETE /oauth/workspace-authorizations/:id/members/:userId(所有成员已授权的应用,以及撤销单个授权;JWT 权限 MANAGE_API_KEYS 或 MANAGE_SETTINGS)。没有可撤销内容时也成功,并发布 AUDIT_CREATED,其中 entity_type 为 oauth_authorization

  • POST /getaway(WebSocket 初始化)

  • GET /realtime/info

  • GET /me/danger-zone, POST /me/danger-zone/delete, DELETE /me/danger-zone/delete

  • GET /me/views/:view、PUT /me/views/:view、DELETE /me/views/:view(已登录成员在当前工作区中为控制台列表设置的个人列布局及排序;view 为 contacts 或 campaign_leads,或为统一收件箱范围侧栏使用 unibox_rail;后者保存包含 favorites、hidden、order 和 section_order 的 layout,而非列设置。属于会话个人配置,任何 API 权限范围均无法访问)

  • GET /invitations, POST /invitations/accept

  • 全部 /organization/*(创建、切换、成员、邀请、转移所有权、头像、危险区域)

    • GET /organization/members 包含各成员的 access_scope(workspace 或 restricted)和 access(scope、campaign_folder_ids、campaign_ids、email_account_ids);GET /organization 携带调用者在各工作区自身的 access_scope。GET /organization/invitations 携带各邀请的 access
    • GET /organization/members/:id/access 和 PUT /organization/members/:id/access(JWT 权限 MANAGE_TEAM;PUT 还要求近期确认)。:id 是成员用户 ID。请求体是完整范围 {"scope": "restricted", "campaign_folder_ids": [], "campaign_ids": [], "email_account_ids": []},会替换已有设置,因此重试得到相同状态,无需 Idempotency-Key。scope: "workspace" 清除资源授权。每个 ID 都必须属于工作区(否则返回 400 invalid_access_resource),每个列表最多 500 项;不能限制所有者(403 owner_access_unrestricted);任何人都不能更改自己的访问权限,且调用者必须持有该成员角色授予的全部权限。返回带有 access 的成员,并发布 AUDIT_CREATED,其中 entity_type 为 organization_member
    • POST /organization/members/invite 接受相同对象作为 access,使受邀者加入时即受限制。邀请和接受时均检查 ID;接受时会移除对期间已删除资源的授权
    • GET /organization/access/suggested-senders?campaign_ids=&campaign_folder_ids=(JWT 权限 MANAGE_TEAM):返回这些营销活动及这些文件夹内营销活动所使用的发件邮箱(显式发件邮箱和发送标签匹配项),每项包含其服务的 campaign_ids。建议本身不授予任何权限
  • GET /website-tracking/settings、PATCH /website-tracking/settings、POST /website-tracking/settings/rotate-key(网站跟踪 代码片段的同意模式、位置精度、允许主机及保留期限;JWT 权限 MANAGE_SETTINGS。轮换无请求体,可安全重复,每次调用签发新密钥)

  • 全部 /subscription/*(checkout、portal、cancel、change-plan、preview-change、enterprise-inquiry、discounts、referrals 等)

  • 全部 /auth/cli/*,下方两个握手路由除外(GET /auth/cli/codes/:code、POST /auth/cli/codes/:code/approve、POST /auth/cli/codes/:code/deny:即 warmbly auth login 的浏览器部分,已登录成员在这里核对 CLI 显示的代码并授权。批准会签发普通 API 密钥,因此要求 MANAGE_API_KEYS 组织权限及近期身份验证,仅限会话调用(API 密钥不得以此方式签发另一密钥),且新密钥权限范围限定在批准者角色允许的范围内。GET /auth/cli/codes/:code?organization_id= 增加 granted_scopes 和 granted_scope_names,说明批准到该工作区将授予的权限)

  • 全部 /pool-link/* 和 /cloud-link/*(自托管预热池关联:批准实例代码、列出和解除实例关联、读取预热池套餐价格并打开结账页面,以及自托管实例上的连接流程和邮箱加入操作)。/cloud-link/* 仅存在于自托管实例。连接属于所选本地工作区,但建立和解除连接(/connect、/connect/poll、DELETE /cloud-link)及操作关联云端工作区的邮箱(/workspace-mailboxes、.../adopt),要求持有 manage_settings 的平台管理员,且其会话已提供第二因素(否则返回 admin_mfa_required)。读取关联及将工作区自己的邮箱加入其中(GET /cloud-link、/mailboxes、加入、暂停、恢复,以及 /oauth/* 下的 Google 和 Microsoft 登录)需要工作区的 MANAGE_EMAILS。GET /cloud-link 包含 legacy_connected;仍使用旧连接的邮箱行包含 legacy。普通 DELETE /cloud-link 只断开所选工作区范围的关联。DELETE /cloud-link?legacy=true 显式断开跨所有工作区的旧版关联,采用相同平台管理员权限。新连接和邮箱加入要求工作区范围,Cloud 工作区只接受一个活跃关联(旧版关联也计入)。POST /pool-link/codes 要求 remote_organization_id,并为支持的客户端返回 workspace_scoped: true。POST /pool-link/codes 和 POST /pool-link/poll 公开且按 IP 限流:它们是实例尚未获得令牌时使用的设备代码握手;/pool-link/instance/* 只接受实例令牌。/pool-link/instance/oauth/*、/pool-link/instance/mailboxes/:id/token、/pool-link/instance/workspace-mailboxes 和 /pool-link/instance/mailboxes/adopt 是云端托管邮箱接口(通过 Warmbly 的 OAuth 应用进行 Google 和 Microsoft 登录,以及代理获取访问令牌);实例侧对应接口为 /cloud-link/oauth/* 和 /cloud-link/workspace-mailboxes/*。/pool-link/instance/redirects(列表),以及 /pool-link/instance/redirects/:domain 上的 GET、PUT、DELETE、POST .../verify,用于 Warmbly Cloud 为调用实例提供的根域名重定向;实例通过带有 served_by: "cloud" 的 PUT /emails/domains/:domain/redirect 驱动这些接口,GET /pool-link/instance 携带 redirects(available、host、limit、used)

  • 全部 /admin/*。DELETE /admin/instance/invitations/expired 要求平台管理员权限 manage_organizations 及已通过 MFA 的会话。它仅清除所有工作区中过期的邀请记录,不更改有效邀请和成员关系,写入管理员审计记录,并返回 { "cleaned": true }。管理面板会在调用前要求确认。

    • GET /admin/instance/health 要求 view_analytics 及已通过 MFA 的管理员会话。返回配置 checks、summary、新增的 execution_coverage(当前为 unreported)和 operational_monitoring_path。没有发现问题并不能证明执行覆盖完整或运行健康。
    • 聚合 PostgreSQL 监控来源(包括同步及工作节点健康样本)统一使用数据库时间基准计算 SQL 阈值、时间窗口及来源/指标观测时间。该观测时间可能晚于快照采集开始的 checked_at;缓存快照保留原始时间。数据库观测不是服务商恢复证据。
    • GET /admin/instance/monitoring 要求 view_analytics 及已通过 MFA 的管理员会话,而非组织 API 密钥权限范围。返回版本 "1" 的只读快照,包含 checked_at、refresh_after、coverage 和按权限裁剪的 sources;HTTP 响应使用 Cache-Control: no-store,后端则共用有效期受限为一分钟的采集缓存。各来源包含可用性、覆盖范围、可为空的观测/范围度量,以及具有可空计数的指标、受影响邮箱/组织、证据时间、条件和可选调查路径。缺少权限时返回带有 permission_denied 的不可用来源占位项,不返回私有指标。来源权限位及解读见 运行监控。不可用不等于零或故障;消息代理的滞后/待处理观测值为正,仍属于 unknown/info,并不能证明吞吐失败。此路由绝不订阅、重放、重连、清除暂停或更改消息代理偏移量/分配。
    • GET /admin/analytics/overview 要求 view_analytics。total_emails_sent 和 emails_sent_today 统计已确认的预热及其他外发邮件,不统计分发。今天按 UTC 自然日计算。发送计数数据库错误会使请求失败,而不是返回零计数。参见 平台管理员发送计数器。
    • GET /admin/organizations 和 GET /admin/organizations/:id 要求 view_organizations。其获客来源字段包含注册时保存的可空 referrer_host,以及 UTM 来源、媒介、活动和着陆路径。列表除现有获客筛选条件外,还接受精确 referrer_host 筛选。来源缺失表示未知,不能证明是直接访问。参见 注册来源归因。
    • GET /admin/warmup-content/overview 包含实际生效的生成控制,要求 view_warmup_pool;PUT /admin/warmup-content/settings 使用 manage_settings 写入实际生效的控制。这些属于平台管理员路由,而非组织 API 密钥权限范围。参见 实际生效的生成策略与停止。
    • POST /admin/organizations/:id/sample-data:要求 manage_testers 及已通过 MFA 的管理员会话。仅向活跃的专用 Test 工作区添加 审核者示例数据集。无请求体。返回 200,包含 organization_id、created(已填充时为 false)和 seeded_at;重试保留已有编辑及删除。普通工作区、已撤销或过期的测试员,或缺少/过期的托管 Test 授权,均返回 400。插入和管理员审计标记一同提交。不连接邮箱、投递邮件、发起外部请求或消耗积分。
    • GET /admin/testers:要求 view_users 及已通过 MFA 的管理员会话。data 中每位测试员可包含其拥有的专用 Test 工作区 test_workspace_id,已填充数据时还包含 sample_data_seeded_at。仅附属于普通工作区的测试员没有这些字段。
    • PUT /admin/users/:id/login-code-exempt:要求 manage_testers、已通过 MFA 的管理员会话及近期确认。请求体 {"exempt": true, "reason": "..."} 豁免该账户的 邮件登录验证码;原因必填(最多 500 个字符),操作管理员记录为授权者。{"exempt": false} 结束豁免、清除已发放的测试员密码,并退出该账户的所有会话。两者均写入管理员审计日志,重复设置相同状态是安全的。未知账户返回 404。GET /admin/users/:id 和 /preview 携带 login_code_exempt、login_code_exempt_reason 和 login_code_exempt_at
    • GET /admin/mailboxes:要求 view_users 及已通过 MFA 的管理员会话。可选 mailbox_id 按精确 UUID 筛选;status=all 包含非活跃邮箱。节点证据链接使用 /mailboxes?mailbox_id=UUID,不受已加载的工作节点分配或之前浏览筛选条件影响。已删除身份返回空结果,而非替代邮箱。

POST /subscription/checkout、POST /subscription/portal、POST /subscription/cancel、POST /subscription/change-plan 和 GET /subscription/preview-change 要求 MANAGE_BILLING 组织权限;读取订阅、限制、试用和功能仅需成员身份。POST /subscription/portal 要求已有 Stripe 计费客户。没有计费客户的工作区会收到 400,错误码为 bad_request,消息提示先完成结账;仅有免费或运维人员授予的套餐不会创建计费客户。

POST /api/v1/internal/email-message-map/lookup 是仅接受节点令牌的邮箱同步读取端点,不属于客户 API 密钥权限范围。JSON 请求体携带 user_id、email_id 和最多 200 个 message_ids(总大小最多 1 MiB)。成功响应为 200,包含 {"mappings": [...]};缺失 ID 被省略,空结果为空数组,而非 404。每项返回映射携带 user_id、email_id、message_id、id 和 thread_id。更新后的 IMAP 工作节点每次批量处理一个邮件信封窗口,不跨处理轮次缓存缺失映射。旧工作节点继续使用单邮件 GET 端点。新工作节点仅在批量路由返回 404 或 405 时回退,并在十分钟后重新检查批量支持,使现有自托管实例在滚动升级期间继续工作。身份验证失败、数据库错误及格式无效的成功响应仍视为失败,不能作为邮件不存在的证据。不更改同步间隔、到达确认或发送授权。

DELETE /cloud-link/mailboxes/:id 移除所选工作区的邮箱加入记录。在 Cloud 上,仅接受实例令牌的 DELETE /pool-link/instance/mailboxes/:remoteId 会先停止托管邮箱参与诊断发送和接收,再释放关联,同时保留其 Cloud 邮箱、登录和历史。停止失败时保留关联以供重试;解除关联失败不会重新启用参与。非托管加入仍按原行为删除其 Cloud 邮箱。整个实例的 DELETE /pool-link/instance 和经工作区授权的实例解绑,在释放关联时保留托管 Cloud 参与状态。这些移除操作天然可重试;远端加入记录不存在时返回 pool_link_mailbox_not_found,自托管客户端将其视为已经释放。

PATCH /cloud-link/mailboxes/:id/participation 仅用于自托管、仅接受 JWT,并要求 MANAGE_EMAILS 和组织所有权。接受类型明确的 mode(diagnostic 或 off)、send、receive 及可选的正数共用/滚动限制。receive 还授权在支持时,对已验证的预热邮件按概率执行移出垃圾邮件、已读、重要标记、加星或旗标操作;不授权回复,也不保证信誉改善。Cloud 通过仅接受实例令牌、限定在调用实例内的 PATCH /pool-link/instance/mailboxes/:remoteId/participation 提供对应操作。这些专用路由防止旧 Cloud 静默忽略新增同意字段;没有参与设置的旧状态不构成显式诊断同意。现有原生生命周期路由在启动/恢复时选择诊断发送和接收,在停止时完全关闭并保留历史。参见 参与设置与发送安全。

对于由 Warmbly Cloud 预热的邮箱,PATCH /emails/:id 通过仅接受实例令牌的 PATCH /pool-link/instance/mailboxes/:remoteId 将 warmup_base、warmup_max、warmup_increase、warmup_reply_rate、warmup_start_time、warmup_end_time、warmup_days 和 warmup(作为暂停或恢复)发送给 Warmbly Cloud,再保存 Cloud 报告的值。仅在 Cloud 应用其部分之后,才在本地写入其余更新,时区也随之一并发送。test_mode、test_send_enabled、test_receive_enabled、shared_daily_limit 和 rolling_recipient_limit 返回 409 cloud_warmup_managed;请使用上方参与设置路由。POST /emails/:id/warmup/start 和 /resume 在 Cloud 恢复邮箱,/pause 在 Cloud 暂停,/stop 返回 409 cloud_warmup_managed。GET /cloud-link/mailboxes 的行携带 settings_observed_at,表示本地副本上次与 Cloud 一致的时间。参见 预热设置 和 拒绝原因。

云端托管 OAuth 另提供 POST /pool-link/instance/oauth/start-correlated、POST /pool-link/instance/oauth/finish-correlated 和 POST /pool-link/instance/mailboxes/adopt-correlated,均仅接受实例令牌,并要求 protocol: 1。已验证实例的响应会声明 managed_consent_protocol: 1。旧版路由保持不变;能力缺失时,不得利用旧副本可能忽略的字段绕过检查。参见 Cloud 路由与恢复约定。

POST /internal/worker/warmup-dispatch 是执行平面内部令牌路由,不属于公开 JWT/API 密钥权限范围。它检查、启动并持久化完成绑定到任务/邮箱/工作节点/nonce 的命令。启动时重新执行权威策略检查;授权未知或被拒绝时,不得执行原生操作。回执、邮件头或模型文本均不提供授权。

POST /internal/email-message-map/arrival 使用现有内部节点令牌。只有带有 X-Warmbly-Arrival-Durable: 1 的 204 才确认已持久化接纳。若权威检查确认所请求的精确邮箱/用户所有权不存在,则返回 503,并通过 X-Warmbly-Arrival-Ownership-Lost 携带请求的邮箱 UUID,不提供持久化确认。更新后的工作节点仅终止该邮箱这一代实例的处理;失败的到达记录保持未确认,保留已存储正文,且不推进服务商游标。普通 503 响应、传输失败、数据库失败和加密失败仍可重试。旧工作节点忽略新标记,继续保留该到达记录;只有后端和工作节点都升级后才能执行此终止处理。这不会清除发送暂停、重发邮件或更改 Kafka 偏移量。

POST /internal/worker/outbound-dispatch、/internal/worker/warmup-actions 和 /internal/worker/diagnostic-auth 使用现有执行平面内部令牌,绝不接受客户 API 密钥。它们绑定当前邮箱/工作节点,并要求协议 2。外发启动还会重新检查任务/组织/服务商/nonce/收件人及当前营销活动或诊断策略。诊断授权和结果提交绑定一个精确、已归属的预热回执及短期 nonce;既不接收无关收件箱邮件,也不信任事件/邮件头声明。未新增任何公开权限范围或权限。详情及限制见 发送安全。

对于已删除、未分配或不再获授权的邮箱,预热操作不返回任何允许的动作。工作节点将这种权威拒绝视为无操作,不接触服务商。数据库或授权服务失败仍返回 503 并重试;拒绝不会授权发送、清除发送暂停或确认到达。

POST /internal/worker/warmup-actions 可接受 filing_id,用于仅整理邮件的操作。只有已获许可、仍在持久化队列中、且精确对应该邮箱及当前工作节点的纯整理工作,才返回 filing_pending: true。整理失败时,此证明允许更新后的工作节点在没有 WarmupFiled 完成事件的情况下结束命令;持久化恢复队列仍负责重试。缺少证明或后端较旧时,保留现有命令重试行为。先部署后端,再部署工作节点以启用此行为。整理成功仍要求完成事件,发布失败仍可重试。没有增加任何发送、到达或按保留策略删除的授权。

推荐奖励与折扣

推荐计划及计费折扣历史属于 /subscription/*,因此仅接受 JWT,永不接受 API 密钥。它们没有 API 权限范围;浏览器调用者受下方组织权限控制。折扣验证和结账端点列于参考文档的 订阅与计费 部分。

方法路径JWT 权限
GET/subscription/referralmanage_billing
POST/subscription/referralmanage_billing
GET/subscription/referral/attributionsmanage_billing
GET/subscription/referral/earningsmanage_billing
GET/subscription/discountsmanage_billing

AI 积分

积分余额、充值购买及交易日志属于 /subscription/*,因此仅接受 JWT,永不接受 API 密钥。购买仅由 Stripe Webhook 完成入账,结账调用本身不会入账。各操作费用、积分包和重置规则,参见 AI 积分 指南。GET /subscription/credits 携带 unlimited(boolean):在采用 BILLING_PROVIDER=none 的部署上为 true,此时绕过积分账本,所有余额及额度字段均为零且无实际含义。

方法路径JWT 权限
GET/subscription/creditsmanage_billing
GET/subscription/credits/transactionsmanage_billing
POST/subscription/credits/checkoutmanage_billing

AI 助手

控制台 AI 助手 Remie 仅接受 JWT:会话仅供发起成员本人使用。消息和批准后的运行通过 Server-Sent Events 流式传输。Remie 执行的每个工具均受成员自身组织权限位控制,因此它绝不会超出成员手动操作的权限。参见 Remie 指南。(API 密钥和 OAuth 调用者可通过 MCP 服务器 或 REST 智能体工具接口 访问相同工具,各工具受自身权限范围控制。)

方法路径JWT 权限
POST/ai/sessions组织成员(使用 AI)
GET/ai/sessions组织成员(使用 AI)
DELETE/ai/sessions组织成员(使用 AI)
DELETE/ai/sessions/:id组织成员(使用 AI)
GET/ai/sessions/:id/messages组织成员(使用 AI)
POST/ai/sessions/:id/messages组织成员(使用 AI,SSE)
POST/ai/sessions/:id/approve组织成员(使用 AI,SSE)
GET/ai/tool-policiesmanage_settings
DELETE/ai/tool-policies/:toolmanage_settings

POST /ai/sessions/:id/approve 接受 {"decision": "approve" | "deny" | "always_allow", "tool_call_id": "..."}。tool_call_id 必填,且必须对应会话正在等待的调用(其 approval_required 事件中的 tool_call_id,或 GET /ai/sessions/:id/messages 返回的 pending.tool_call_id);其他值返回 409 approval_not_pending,对同一调用作出第二次决定也如此。always_allow 仅在成员具有 manage_settings 且工具允许设置为始终允许时保存工作区策略,否则只批准本次调用。approval_required 事件和 pending 携带 arguments(所有参数以缩进 JSON 展示,键排序,最多 16 KiB,附带 arguments_truncated)、发送操作的 preview(from、to、subject、body、body_html),以及 always_allow_offered。

GET /ai/tool-policies 列出助手无需询问即可运行的工具(tool_name、created_by、created_by_name、created_at);DELETE /ai/tool-policies/:tool 撤销其中一个。两者的审计类型均为 ai_tool_policy。

AI 技能

AI 功能遵循的组织操作指南(参见 AI 技能 指南)。JWT 调用者需要 manage_settings,API 密钥需要 AI_AGENT 权限范围。通过 API 密钥创建、编辑或删除操作指南,还要求密钥创建成员持有 manage_settings。

方法路径权限
GET/ai/skillsmanage_settings / AI_AGENT
POST/ai/skillsmanage_settings / AI_AGENT
PATCH/ai/skills/:idmanage_settings / AI_AGENT
DELETE/ai/skills/:idmanage_settings / AI_AGENT

智能体工具(REST)

通过普通 HTTP 提供 AI 工具登记表,供不支持 MCP 的函数调用智能体使用(参见 智能体工具)。与 MCP 端点一样,需要 AI_AGENT(JWT 调用者为 use_ai);随后各工具检查自身权限,列表仅显示调用者可用的工具,且永不暴露发送类工具。

方法路径权限
GET/ai/toolsuse_ai / AI_AGENT,然后检查各列出工具的权限
POST/ai/tools/:name/calluse_ai / AI_AGENT,然后检查所调用工具的权限

已连接的 MCP 服务器

助手可使用其工具的外部 MCP 服务器(参见 连接 MCP 工具)。仅接受 JWT,并要求 manage_settings;Bearer 令牌使用组织密钥密封保存,绝不返回。

方法路径JWT 权限
GET/ai/connectionsmanage_settings
POST/ai/connectionsmanage_settings
PATCH/ai/connections/:idmanage_settings
DELETE/ai/connections/:idmanage_settings
POST/ai/connections/:id/refreshmanage_settings

Slack

Slack 面板的路由。仅限会话调用:关联操作将 Slack 账户绑定到已登录用户,而 API 密钥没有可供绑定的用户身份。设置变更和移除关联会发布 AUDIT_CREATED,其中 entity_type 为 integration。

方法路径JWT 权限
GET/integrations/slack/status组织成员。所有人可获取 app_configured、interactive_configured 和 my_link(始终为调用者自身的关联);connection、settings 和 missing_scopes 仅提供给具有 manage_settings 或 use_integrations 的成员(否则分别省略、为 {} 和 []);links(所有成员的关联)仅提供给具有 manage_settings 的成员
GET/integrations/slack/channelsmanage_settings 或 use_integrations。返回公开频道及机器人所在的私有频道,按 q 筛选,最多 200 项,采用 data 加 pagination 的结构
PUT/integrations/slack/settingsmanage_settings。默认 channel、按分类的 routes、assistant_disabled、assistant_dm_only、inbox_channel(列表中的频道 ID;为空时关闭 收件箱频道),以及 inbox_scope(replies,默认值,或 all)。收件箱频道必须对机器人可见,且不能是 Slack Connect 频道,否则返回 400。具有幂等性:替换整个设置对象
GET/integrations/slack/link/:code已登录,可处于任意工作区。预览机器人按钮携带的关联信息:organization_id、organization_name、is_member、slack_team_id、slack_team_name、slack_user_id、slack_user_name 和 slack_user_avatar(以 Slack 当前报告为准,后两者均可能为空)、user_email(调用者 Warmbly 邮箱)、email_matches(Slack 账户邮箱是否与调用者 Warmbly 邮箱相同)、verify_available(是否可通过 Slack 登录确认关联)及 expires_at。未知或过期代码返回 404 slack_link_invalid
POST/integrations/slack/link/verify已登录,且为代码所属工作区的成员(否则返回 403 forbidden)。提交机器人按钮中的 code;以 200 返回 url,指向代码所属 Slack 工作区的“通过 Slack 登录”页面。Slack 返回集成 OAuth 回调,再将 code 和 state 传给打开窗口的页面。Slack 应用没有客户端凭据时返回 503 slack_verify_unavailable
POST/integrations/slack/link已登录,且为代码所属工作区的成员(否则返回 403 forbidden)。提交机器人按钮中的 code;调用者 Warmbly 邮箱与代码中 Slack 账户邮箱不同时,还需提供 Slack 登录返回的 slack_code 和 state(缺少时返回 403 slack_link_email_mismatch,代码仍可继续使用)。Slack 登录结果必须属于此调用者、对应此代码及代码中的 Slack 账户(否则返回 403 slack_verify_failed 或 slack_verify_wrong_account)。以 201 返回关联,并替换该 Slack 账户先前的关联。代码仅可使用一次,因此重复调用以 404 slack_link_invalid 拒绝
PATCH/integrations/slack/link组织成员,自身关联。dm_notifications。调用者在此工作区没有关联时返回 404 slack_not_linked
DELETE/integrations/slack/link组织成员,自身关联。返回 204,没有关联时也如此,因此可安全重复调用
DELETE/integrations/slack/links/:idmanage_settings。移除任意成员的关联。返回 204

接受代码的两个 /integrations/slack/link 路由无需选定工作区,因为代码已指明工作区。GET /integrations/slack/status 报告 app_configured(实例有 Slack 应用)和 interactive_configured(还具有签名密钥,因此助手和按钮可用),使客户端在调用其他接口前了解可用能力。工作区尚未连接 Slack 时,设置和频道路由返回 404 slack_not_connected。错误码见 404 和 503。

MCP 服务器

POST /v1/mcp 通过 模型上下文协议(Model Context Protocol) 的流式 HTTP 传输提供工具登记表。接受具有 AI_AGENT 的 API 密钥或 OAuth 2.1 访问令牌(未认证请求获得 RFC 9728 发现质询)。各工具按自身权限范围控制,tools/list 仅反映凭据允许的内容,且永不暴露发送类工具。适用每密钥限流。

公开端点

控制台仅用于显示的 POST /v1/dashboard-image 端点接受会话 JWT 和 {"url":"https://..."},返回图片字节。不支持 API 密钥。它通过当前存储读取本实例拥有的公开对象,或获取公开 HTTPS 图片,不转发浏览器凭据、Cookie 或来源信息。适用读取速率限制;请求体最多 16 KiB,URL 最多 8,192 个字符,图片最多 5 MiB,请求最多十秒。非图片、非公开目标、不安全重定向及不支持的端口均拒绝。不存储或更改任何内容,因此重试无需幂等键。保存和发送的邮件保留原始 URL。

POST /v1/dashboard-image/public 采用相同请求体及图片限制,但只接受本实例拥有的公开对象和 Slack 登录头像服务商(avatars.slack-edge.com 和 secure.gravatar.com/avatar/)。按 IP 限流,不能匿名获取任意客户 URL。

  • GET /health
  • POST /auth/cli/code、POST /auth/cli/poll(CLI 设备代码握手,按 IP 限流。必须公开,因为 CLI 在流程完成前没有凭据。POST /auth/cli/code 返回 device_code、user_code、verification_uri、verification_uri_complete、expires_in 和 interval;成员作出决定前,轮询返回 {"status":"pending"},之后返回 {"status":"approved"} 并且仅一次携带签发的密钥,或返回 {"status":"denied"}。未知或过期的 device_code 返回 404,防止轮询方探测有效握手)
  • POST /webhook/stripe(Stripe 签名)
  • POST /api/v1/integrations/hubspot/webhooks(HubSpot 应用 Webhook,使用应用客户端密钥生成的 X-HubSpot-Signature-v3 签名验证,超过五分钟则拒绝。投递只会提前对指定记录的下一次读取;参见 HubSpot)
  • POST /api/v1/integrations/pipedrive/webhooks/:connectionId(工作区切换到 Pipedrive 时,Warmbly 为单个连接注册的 Pipedrive Webhook。通过 HTTP Basic 身份验证,密码由连接及应用客户端密钥派生。投递只会提前对指定记录的下一次读取;若没有工作区使用该连接作为 CRM,则返回 410。参见 Pipedrive)
  • GET 和 POST /api/v1/integrations/pipedrive/app/panel、/app/enroll 和 /app/pause(Pipedrive 联系人和商机页面中的 Warmbly JSON 面板及两个 JSON 弹窗)。Pipedrive 使用应用客户端密钥为每次调用签发 JWT,通过 token 查询值传递,并固定为 HS256;其中指定的用户和公司必须与 userId 和 companyId 查询值匹配,重复参数值会被拒绝。公司标识选中唯一一个处于 Pipedrive 模式、且与其有有效连接的工作区,每次调用均以匹配该 Pipedrive 用户的成员身份及权限执行。参见 在 Pipedrive 中工作
  • POST /api/v1/integrations/hubspot/app/card、/app/enroll、/app/pause(HubSpot 联系人记录上的 Warmbly 卡片),以及 POST /api/v1/integrations/hubspot/actions/enroll、/actions/campaigns(“添加到 Warmbly 营销活动”工作流操作)。HubSpot 使用应用客户端密钥为每个请求签名(X-HubSpot-Signature-v3,基于公开后端 URL)。卡片路由从 HubSpot 追加的查询值获取门户和 HubSpot 用户,每项必须恰好出现一次,并以该用户匹配到的成员身份及权限执行;Webhook 和工作流操作路由拒绝携带这些值的请求。门户标识选中唯一一个处于 HubSpot 模式、且与其有有效连接的工作区。参见 在 HubSpot 中工作
  • POST /webhook/campaign、/webhook/email、/webhook/user-email(来自 Cloud Tasks 的 Google OIDC 令牌)
  • GET /addresses/google/callback、GET /addresses/outlook/callback(OAuth 跳转页面)
  • POST /oauth/token、POST /oauth/revoke(OAuth 令牌端点,通过客户端 ID 和密钥验证,公开客户端则使用 PKCE)
  • POST /oauth/register(OAuth 动态客户端注册,RFC 7591;公开且按 IP 限流)
  • GET /.well-known/oauth-authorization-server、GET /.well-known/oauth-protected-resource(OAuth 发现元数据)

位于后端主机上,但在 /v1 之外,由 Slack 调用,绝不由 API 密钥或会话调用:

  • POST /api/v1/integrations/slack/events、POST /api/v1/integrations/slack/interactivity(Slack 签名)。每个请求必须携带有效的 Slack X-Slack-Signature,使用实例签名密钥及五分钟内的时间戳生成,请求体最多 1 MiB。签名无效返回 401 unauthorized,在签名验证通过前不解析请求体中的任何内容。未设置 SLACK_SIGNING_SECRET 时返回 503 slack_not_configured。端点在 Slack 的三秒时限内响应,之后再处理工作。参见 Slack 应用

位于跟踪服务(TRACKING_DOMAIN 主机,而非 API),同样公开并按来源限流:

  • GET /t/o/:task_id.png(打开跟踪像素)、GET /c/:link_id(点击重定向)
  • GET /tracking.js(网站跟踪代码片段)、POST /p(页面浏览接收;JSON 请求体最多 8 KB,超过额度返回 429,否则返回 204。请求中的任何内容均不能指定联系人)
  • 访问工作区指向此服务的 发件域名根地址(或其 www)。对于已验证域名,除 /health 外的所有路径均在上述路由之前,以 302 重定向到其网站,并带有 Cache-Control: public, max-age=300;未知主机返回 404。表单服务对已验证重定向域名采用相同响应方式

定时任务

GET /admin/jobs 要求管理员权限 view_analytics,在 data 中返回已注册循环任务及保留的已停用记录。每行包含服务、间隔、最近记录的状态和错误、执行计数器及记录的时间安排。retired_at 出现时,表示显式归类为停用的时间戳,不能证明最后一个进程何时停止。停用记录及其历史值仍显示在 Jobs 中;在运行监控中,它们不属于当前运行、逾期、失败或成功的任务。

POST /admin/jobs/:name/run 要求管理员权限 manage_settings。它请求已注册循环任务在下一次轮询时运行,不直接执行任务本身。不存在和已显式停用的记录返回 404 not_found。停用循环不能认领新的计划时段,也不能接收手动请求。停用不会中断已经获准运行的任务,也不会删除其完成证据。

迁移 286 仅将已从应用移除的后端 fleet_quarantine 循环归类为停用。其他旧任务或停滞任务仍保持活跃,并保留监控警告。不按任务年龄自动停用。重新注册循环会重新激活记录,并清除旧的待运行请求,但不重置执行计数器或错误。

平台节点诊断

位于后端源站、/v1 之外的路由要求普通 Bearer 会话、当前有效的管理员权限及会话 MFA。工作区 API 密钥/OAuth API 令牌无法使用。

方法及路径现有管理员权限
POST /admin/auth/device/describe任意非零管理员权限
POST /admin/auth/device/decide任意非零管理员权限 + 近期身份验证
GET /admin/fleet/nodes/:id/logsVIEW_WORKERS
GET /admin/fleet/nodes/:id/brokerVIEW_WORKERS 和 VIEW_ANALYTICS

公开设备启动/轮询端点为 POST /v1/auth/cli/admin/code 和 /poll。参见 精确身份验证结构。没有远程 shell、任意执行端点或管理员 API 密钥。变更仍通过现有受权限控制的管理员端点和审计轨迹执行。

近期诊断证据

GET /admin/fleet/nodes/:id/logs 接受可选 after/before(含边界的 RFC3339 时间戳,after 不得晚于 before)、level(info、warn、error)、mailbox_id(邮箱账户 UUID,不是文件夹或邮件)及 limit(整数 1..200,默认 200)。结果最新在前,每个节点最多保留一小时和 1,000 个事件;过期或因数量限制淘汰的证据无法恢复。这是允许列表内的进程证据,不是完整日志导出。

响应 200(Cache-Control: no-store):

{
  "node_id": "<node UUID>",
  "availability": "fresh", "coverage": "partial",
  "reason": "allowlisted_evidence_only", "observed_at": "2026-10-10T06:10:00Z",
  "capture": {
    "protocol": 1, "run_id": "<process UUID>", "started_at": "2026-10-10T06:00:00Z",
    "observed_at": "2026-10-10T06:09:58Z", "received_at": "2026-10-10T06:09:59Z",
    "dropped": 2
  },
  "events": [{
    "id": "<event UUID>", "observed_at": "2026-10-10T06:09:50Z",
    "event": "sync_control_plane_held", "level": "warn", "category": "control_plane",
    "mailbox_id": "<mailbox account UUID>", "http_status": 503, "count": 1
  }],
  "oldest_retained_at": "2026-10-10T06:09:50Z", "newest_retained_at": "2026-10-10T06:09:50Z",
  "retained_count": 1, "truncated": false, "retention_seconds": 3600, "max_events": 1000
}

尚未观测到时省略 capture。最早/最新时间及数量描述整个保留窗口,而非筛选后的行。truncated 表示响应条数上限之外仍有匹配的保留记录。dropped 统计该进程启动后已知的队列溢出/传输重试耗尽批次数,而非整个生命周期的丢失量;在 run_id 改变时重置。崩溃丢失、安装采集功能前的事件及丢失的确认无法完整度量:即使接收成功但确认丢失,重试耗尽的批次仍计为丢弃。TTL/数量淘汰属于预期保留策略,而非传输丢失。

可用性 / 原因含义
unavailable / log_credential_unavailable旧版/手动工作节点,或 Redis 加入状态丢失;请重新加入
unavailable / capture_not_observed已加入,但尚未收到升级后的采集数据;可能是旧工作节点
unavailable / cache_unavailable无法读取历史,不代表错误数为零
stale / no_recent_capture采集观测超过两分钟;仍可能显示保留记录
fresh / no_recent_evidence近期空采集,不能证明服务商健康
fresh / allowlisted_evidence_only新近的部分证据,绝不能据此推断完整覆盖或健康状态

固定事件结构:UUID id、RFC3339 observed_at、允许列表中的 event、标准 level/category、可选邮箱 UUID,以及数值 count(0..1,000,000)。仅 sync_control_plane_held 保留数值 HTTP 状态(100..599),包括实际同步映射/控制平面的 503 响应。

事件类别 / 级别观测到的行为
sync_control_plane_heldcontrol_plane / warn实际同步控制平面调用失败;中止本轮处理,保持游标不变
sync_message_deferredcontrol_plane / warn未发布映射的清理失败,跳过本轮处理
mailbox_provider_unreachableprovider / warn实际同步连接/传输失败
mailbox_provider_auth_failedprovider / warn实际同步身份验证/授权失败
mailbox_provider_throttledprovider / warn实际同步限流
mailbox_provider_sync_completedprovider / info此前传输失败后,观测到一次完整处理成功
sync_folder_skippedsync_policy / info同步策略排除的文件夹数
sync_message_deferred_by_policysync_policy / info某轮同步中被延后的邮件数
sync_skipped_folder_search_failedprovider / warn实际被排除文件夹搜索失败
sync_legacy_arrivalcompatibility / warn使用了现有旧版到达回退机制
worker_errorworker_runtime / error仅工作节点 Zap 错误级别,不包含任意日志文本

历史还报告 generic_error_coverage: "unavailable" 和 generic_error_reason: "unhooked_runtime_sources"。通用运行时错误采集目前仅接入工作节点 Zap。工作节点 Zerolog 和消费者进程 standard-log/Zerolog 错误尚未采集。显式允许列表内的同步/服务商/控制平面决策采集点仍独立存在且保持不变。新近的空采集(包括消费者进程采集)绝不能证明运行时错误为零或系统健康。这些字段描述的是来源覆盖缺失,不是当前故障。

不转发地址、主题、正文、邮件头、原始错误、文件夹名称或服务商凭据。未知自由格式字段被丢弃;类别和级别在传输前,以及接收/读取时重新构建。未知事件被拒绝。证据不会更改同步租约、游标处理、到达接纳或发送授权。

节点数据接收

POST /api/v1/internal/fleet/nodes/:id/logs 仅接受加入时签发、专属于该节点的 Authorization: Bearer <NODE_LOG_TOKEN>。现有节点集群加入令牌授权在 env_b64 中签发此凭据。不接受共用消息代理/内部令牌;哈希精确绑定一个已注册节点,并在接收时进行原子复核。重新加入会轮换凭据;删除节点会撤销凭据并清除日志状态。此凭据仅授予证据提交权限,不授予邮箱或命令访问权限。

不存在用消息代理密钥刷新日志凭据的端点:现有消息代理密钥验证节点集群身份,不证明某个节点 UUID 的所有权。现有节点必须升级,并使用相同 UUID 重新执行已认证的加入流程。常规加入脚本从现有 node.env 读取 UUID,保留 node.local.env 并重启服务;不要移除配置目录或删除集群节点记录。在收到采集数据前,可用性为不可用,而非健康。Redis 加入哈希丢失时也需要采用相同安全重新加入流程,且不会导入历史日志。参见 升级顺序与覆盖范围。

请求 JSON(最多 32 KiB、32 个事件;事件使用上述结构):

{
  "protocol": 1, "batch_id": "<UUID, stable across retries>", "run_id": "<process UUID>",
  "started_at": "2026-10-10T06:00:00Z", "observed_at": "2026-10-10T06:09:58Z",
  "dropped": 2, "events": []
}

空批次仅报告采集覆盖情况。批次时间必须在接收前两分钟内,且不得超前一分钟。事件必须位于一小时保留期内,且不得超前一分钟。started_at 必须存在,且不得晚于观测时间。重复批次 ID 在一小时内具有幂等性;旧批次不能覆盖较新的采集元数据。采集周期为五秒,队列容量 256 个事件,最多尝试三次,使用有上限的退避和五秒 HTTP 超时。采集绝不等待网络或队列空间。已认证请求上限为每节点每分钟 30 次。成功返回 204;错误采用标准响应结构:400 bad_request(协议/时间/边界/事件无效)、401 unauthorized(凭据缺失、节点不匹配或已撤销)、404 not_found(已注册节点不存在)、429 rate_limit_exceeded(Retry-After: 60)及 503 service_unavailable(依赖问题)。

消息代理的已提交消费进度滞后量

GET /admin/fleet/nodes/:id/broker 接受已注册工作节点 UUID,不允许覆盖主题或消费者组。现有只读范围保持独立:commands 观测 worker-<UUID> / w.<UUID>;results 观测 consumer-group / jobs.worker-events,这是共用结果,不能归因到该工作节点。不新增消费者权限范围,也不更改偏移量。

响应 200 包含 node_id、RFC3339 observed_at、commands、results 和 note。各部分使用现有 MonitoringSource:id、availability、coverage,可选 reason、observed_at、checked_at,已测量/预期范围,以及 metrics。成功指标为 committed_lag(消息数)和 members,包含计数、观测/证据时间戳、condition: "unknown"、严重程度及提示说明。仅此专用端点启用滞后分区详情:

{
  "broker": {
    "consumer_group": "worker-<UUID>", "topics": ["w.<UUID>"],
    "partitions": [{"topic":"w.<UUID>","partition":0,"earliest":10,"committed":16,"latest":22,"committed_lag":6}]
  }
}

会验证所有请求的主题/分区,以及已提交/最早/最新偏移量;分区 ID 必须非负,每个范围最多 128 个分区,按主题/分区排序。缺少提交、偏移量超出保留范围、分区不匹配、滞后为负或溢出、权限错误和超时均视为不可用,绝不将其截为零。失败指标计数为 null,不含消息代理详情,条件为 unknown,并记录尝试观测的时间。原因包括 dependency_missing、resource_absent、permission_denied、timeout、collection_failed;非 Kafka 或不支持的消息总线返回 unsupported 和空指标。某个范围失败不会隐藏另一个成功范围。整体采集时限为八秒。

滞后 不 等同于投递、服务商健康、吞吐量、未提交的在途工作、队列清空时间或故障。仅凭成员数量也不能判定故障。错误:400 bad_request(UUID/非工作节点/无效日志筛选)、401 unauthorized、403 admin_mfa_required/forbidden、404 not_found、503 service_unavailable(节点登记表)。日志 Redis 读取失败则返回 200,明确标注覆盖不可用。成功诊断使用 Cache-Control: no-store。

内部预热恢复

这些控制平面端点使用现有节点内部凭据,不使用 API 密钥、控制台 JWT 或节点日志凭据。基础路径为 /api/v1/internal,而非上方公开 API 基础路径。不引入新节点身份或凭据交换。

方法内部路径权限范围
POST/worker/warmup-actions检查当前邮箱分配及允许操作;精确匹配的待处理单文件整理工作可返回带版本的整理恢复证明
POST/worker/warmup-actions/defer在当前邮箱分配下,为精确匹配的待处理整理操作提交单调不减的服务商重试时间

延后操作接受 mailbox_id、worker_id、filing_id 和绝对 provider_retry_at 时间戳。仅在提交后才返回成功 persisted: true,并提供 filing_recovery 证明,包含协议 1、相同的三个 ID 及保留的时间戳。请求更短时间绝不会缩短现有服务商暂停或普通重试租约。延后操作没有 GET 变更,也不会产生新的整理成功事件。

对于精确匹配的整理命令,若待处理整理已完成、不存在、归属其他资源或操作载荷不同,升级后的后端不返回任何允许操作。工作节点跳过服务商整理,且不会为此拒绝发出整理成功事件。未跟踪的操作保持现有准入行为。

标识符或时间无效返回 400;工作已过时、已删除、归属其他资源或不被允许时返回 403;授权能力不受支持或数据库失败返回 503。响应使用 Cache-Control: no-store。客户端不会接受未标记、格式错误、版本不支持或范围不正确的回复作为持久化延后证明。现有旧后端的重试行为保持不变;旧工作节点不实现服务商重试时间下限。先升级后端及来源实例数据处理说明,参见 预热重连恢复。

说明

  • 当路由同时列出 JWT 权限和 API 权限时,同时支持 JWT 和 API 密钥的身份验证中间件对浏览器调用者检查 JWT 用户的组织角色,对 API 密钥调用者检查密钥权限位掩码。两者是独立检查:除创建时授予的权限外,用户角色不会进一步限制 API 密钥的操作能力。
  • 每个 API 密钥请求都记录到 api_key_usage_logs,包含端点模式(例如 /campaigns/:id)、方法、IP、user-agent、响应状态及耗时毫秒数。JWT 请求不在此处记录。
  • 速率限制类别(X-RateLimit-* 请求头)按底层用户而非密钥划分;同一用户签发的所有密钥共用该用户的额度。

另请参阅

本页目录