NueForm

Webhook 负载

NueForm webhook 负载模式的完整参考,包括 form.submitted 事件结构、按问题类型的答案格式和测验结果。

每个 NueForm webhook 请求在请求体中发送一个 JSON 负载。本页记录了每种事件类型的完整负载模式。

通用结构

所有 webhook 负载共享这些顶级字段:

字段类型描述
eventstring事件类型(例如 form.submitted)
formIdstring表单的唯一 ID
formTitlestring提交时表单的标题
responseIdstring回复的唯一 ID
answersarray答案对象数组
respondentobject 或 null当表单要求登录时的已登录受访者身份。匿名提交为 null。请参阅 受访者身份。
submittedAtstring事件分发时的 ISO 8601 时间戳

form.submitted 负载

这是受访者提交完整表单回复时发送的负载。

完整示例

json
{
  "event": "form.submitted",
  "formId": "507f1f77bcf86cd799439011",
  "formTitle": "Customer Feedback Survey",
  "responseId": "507f1f77bcf86cd799439022",
  "answers": [
    {
      "questionId": "507f1f77bcf86cd799439033",
      "value": "Jane Doe",
      "label": "What's your name?",
      "type": "short_text"
    },
    {
      "questionId": "507f1f77bcf86cd799439044",
      "value": "jane@example.com",
      "label": "What's your email address?",
      "type": "email"
    },
    {
      "questionId": "507f1f77bcf86cd799439055",
      "value": 4,
      "label": "How would you rate your experience?",
      "type": "rating"
    },
    {
      "questionId": "507f1f77bcf86cd799439066",
      "value": "The onboarding flow was smooth and intuitive.",
      "label": "What did you like most?",
      "type": "long_text"
    },
    {
      "questionId": "507f1f77bcf86cd799439077",
      "value": ["c3a1e5f2-8b4d-4f6a-9e21-7d0b3c8a5f14", "9b7e2d41-5c3f-4a8e-b6d0-1f2a4c6e8b93"],
      "label": "Which features do you use?",
      "type": "multiple_choice"
    },
    {
      "questionId": "507f1f77bcf86cd799439088",
      "value": true,
      "label": "Would you recommend us?",
      "type": "yes_no"
    }
  ],
  "respondent": {
    "id": "507f1f77bcf86cd799439016",
    "name": "Jane Smith",
    "email": "jane@example.com",
    "auth_method": "sso"
  },
  "submittedAt": "2025-03-15T14:32:07.123Z"
}

字段参考

顶级字段

event --- string

此事件类型始终为 "form.submitted"。

formId --- string

表单的 MongoDB ObjectId。这是一个 24 字符的十六进制字符串。

formTitle --- string

webhook 触发时表单的可读标题。请注意,如果您后来重命名表单,之前已发送的 webhooks 仍然包含旧标题。

responseId --- string

存储回复的 MongoDB ObjectId。您可以使用它通过 Responses API 获取完整回复,或作为幂等键去重 webhook 传递。

submittedAt --- string

ISO 8601 时间戳,指示 webhook 分发的时间。这是在分发时生成的,将非常接近(但不一定完全相同于)数据库中回复的 submittedAt 字段。

respondent --- object 或 null

提交回复的已登录用户的身份,仅当表单要求登录(requireLogin: true)时才会公开。所有匿名提交均为 null。请参阅下方的 受访者身份 以获取完整模式和行为。

答案对象

answers 数组中的每个条目代表单个问题的回复:

字段类型描述
questionIdstring问题的 MongoDB ObjectId
valueany受访者的答案(格式因问题类型而异)
labelstring仅限网页提交。问题的标题(纯文本),使用受访者作答时所用的语言。
typestring仅限网页提交。问题类型,例如 short_text 或 matrix。
subLabelsobject仅限网页提交,用于带子字段的问题,例如联系信息、地址或问题组。将每个子字段的 ID 映射到其标签。
valueLabelsobject适用于网页提交和电话提交,用于选项、行或列来自变量的问题。此时 value 保存的是条目的值,该映射给出每个所选值的标签。对于矩阵题,键为 row:<值> 和 column:<值>。固定列表的答案不包含此字段。

电话提交的答案包含 questionId、value,对于取自变量的列表还包含 valueLabels。网页答案还可能包含 viewedAt 和 answeredAt:问题显示和作答的时间,为来自受访者设备的 ISO 8601 时间戳。今后可能会增加更多字段,请忽略您用不到的字段。

对从变量加载的列表,网页答案如下所示:

json
{
  "questionId": "507f1f77bcf86cd799439099",
  "value": "siamese",
  "label": "Which breed is your cat?",
  "type": "dropdown",
  "valueLabels": { "siamese": "Siamese" }
}

同一答案如果是在电话通话中给出的,则不包含 label 和 type。

按问题类型的答案值

每个答案对象中的 value 字段因问题类型而异。以下是每种类型的格式:

文本输入

问题类型值类型示例
short_textstring"Jane Doe"
long_textstring"I really enjoyed the product..."
emailstring"jane@example.com"
phonestring"+1 (555) 123-4567"
numbernumber42
urlstring"https://example.com"

选择题

问题类型值类型示例
multiple_choice(单选)string"c3a1e5f2-8b4d-4f6a-9e21-7d0b3c8a5f14"
multiple_choice(多选)array<string>["c3a1e5f2-8b4d-4f6a-9e21-7d0b3c8a5f14", "__other__:Word of mouth"]
dropdown(单选)string"e0c4a7d9-2f16-4b3e-8a57-c19d6f2b4e80"
dropdown(多选)array<string>["e0c4a7d9-2f16-4b3e-8a57-c19d6f2b4e80", "5d8f1b36-a9e2-4c07-b3d4-6e1a9f7c2b58"]
yes_nobooleantrue

value 保存的是选项 ID,而不是标签:即问题 choices 中每个所选选项的 id。构建器以 UUID 的形式创建这些 ID。API 和 MCP 服务器 也接受没有 id 的选项,例如 { "label": "Search engine" };此时在网页答案中,value 保存的是该选项的 label,而不是 ID。multiple_choice 和 dropdown 发送单个字符串;当 allowMultiple 为 true 时,发送字符串数组。图片选项(layout: "blocks")同样是 multiple_choice 问题。

如果受访者选择 其他,该条目为 __other__: 加上其输入的文本,如上表示例所示。电话通话会把“其他”答案保存为来电者的原话,不带该前缀。

Webhook 不会发送固定列表的标签。要显示标签,请在问题的 choices 中按 ID 查找,获取表单 会返回这些选项;对于没有 id 的选项,value 保存的已经是它的 label。当选项来自变量时,value 保存的是条目的值,答案的 valueLabels 给出它们的标签,请参阅答案对象。

评分题

问题类型值类型示例范围
ratingnumber41 到 steps(默认 5)
opinion_scalenumber7min 到 max
npsnumber90 到 10

日期和时间

问题类型值类型示例
datestring"2025-03-15"

日期字符串格式匹配问题上配置的 dateFormat 属性(默认为 YYYY-MM-DD)。

法律条款和陈述

问题类型值类型示例
legalbooleantrue
statementstring""(始终为空——陈述不收集数据)

排序

问题类型值类型示例
rankingarray<string>["5d8f1b36-a9e2-4c07-b3d4-6e1a9f7c2b58", "c3a1e5f2-8b4d-4f6a-9e21-7d0b3c8a5f14", "71a4c9e0-3b5d-4f82-9c16-d2e8a0b7f345"]

数组按受访者排定的顺序(从第一到最后)保存选项 ID;在网页答案中,保存时没有 id 的选项会以其 label 代替 ID 出现。将这些 ID 与标签对应的方法与选择题相同。

矩阵

问题类型值类型示例
matrixobject{ "Speed": "Satisfied", "Price": "Neutral" }

对于行和列都固定的矩阵,对象将每一行的标签映射到所选列的标签。当行或列来自变量时,它映射的是行的值到列的值,受访者看到的标签则保存在答案的 valueLabels 中,键为 row:<值> 和 column:<值>。

文件上传

问题类型值类型示例
file_uploadstring"https://storage.nueform.io/uploads/abc123.pdf"

值为上传文件在 NueForm 存储中的 URL。

签名和绘图

问题类型值类型示例
signaturestring"data:image/png;base64,iVBOR..."
drawingstring"data:image/png;base64,iVBOR..."

两者都返回捕获图像的 base64 编码 PNG data URI。

录制

问题类型值类型示例
recordingstring"https://storage.nueform.io/recordings/abc123.webm"

值为上传录制文件的 URL。

复合问题

复合问题类型(contact_info、address、question_group、multi_question_page)只产生一个答案条目,使用复合问题自身的 questionId。其 value 是一个以子字段 ID 为键的对象。联系信息和地址使用内置 ID,例如 first_name 和 zip_code;问题组或多问题页面使用其中每个问题的 ID。每个子字段的值采用其自身问题类型的格式。网页答案还包含 subLabels,它将每个子字段 ID 映射到其标签。

例如,一个 contact_info 问题会产生:

json
{
  "questionId": "507f1f77bcf86cd7994390aa",
  "value": {
    "first_name": "Jane",
    "last_name": "Doe",
    "phone_number": "+1 555-0100",
    "email": "jane@example.com",
    "company": "Acme Inc."
  },
  "label": "How can we reach you?",
  "type": "contact_info",
  "subLabels": {
    "first_name": "First Name",
    "last_name": "Last Name",
    "phone_number": "Phone Number",
    "email": "Email",
    "company": "Company"
  }
}

同一答案如果是在电话通话中给出的,value 相同,但不包含 label、type 和 subLabels。

受访者身份

当表单配置了 requireLogin: true 时,每次接受的提交都会绑定到已登录的用户。Webhook 负载通过 respondent 字段向表单所有者公开该身份。对于所有其他提交,该字段为 null。

模式

json
{
  "respondent": {
    "id": "507f1f77bcf86cd799439016",
    "name": "Jane Smith",
    "email": "jane@example.com",
    "auth_method": "sso"
  }
}
字段类型描述
idstring受访者的用户 ID。
namestring受访者帐户上的显示名称。
emailstring受访者帐户上的电子邮件地址。
auth_methodstring"sso" 或 "login" 之一。"sso" 表示受访者通过单点登录是表单团队的成员;"login" 表示任何其他受支持的身份验证方法。

何时填充 respondent

respondent 仅在以下情况下填充:

  1. 表单将 requireLogin 设置为 true,并且
  2. 提交者因为表单要求而在提交前登录。

当 requireSsoLogin 也为 true 时,只有通过 SSO 成为表单团队成员的用户才能进入提交步骤,因此每个填充的 respondent 都将具有 auth_method: "sso"。

何时 respondent 为 null

为了下游解析的可预测性,该字段始终存在于 JSON 中,并在以下任一情况下为 null:

  • 表单不要求登录(requireLogin 为 false)。
  • 提交者是匿名的。
  • 回复是通过提交后同意流程("认领此回复"提示)保存的。永远不会有附加身份的同意保存回复出现在 webhook 负载中——它们仅存储在用户的"我的回复"视图中,不会公开给 webhook 接收者。

Webhook 负载仅公开 因表单要求 而登录的受访者的身份。通过提交后同意收集的身份会被有意保留在 webhooks 之外,以尊重受访者的隐私和所有者的洞察之间的边界。

测验结果

对于以测验模式运行的表单(knowledge_quiz、lead_qualification 或 match_quiz),存储的回复包含 quizResults 对象。虽然此对象不直接包含在 webhook 负载中,但您可以使用 webhook 中的 responseId 通过 Responses API 检索它。

quizResults 对象具有以下结构:

json
{
  "formMode": "knowledge_quiz",
  "score": 7,
  "correctAnswers": 7,
  "totalScorableQuestions": 10,
  "maxScore": 10,
  "matchedEndingId": "507f1f77bcf86cd799439099"
}
字段类型描述
formModestring测验模式:knowledge_quiz、lead_qualification 或 match_quiz
scorenumber受访者的总分
correctAnswersnumber正确回答的问题数(仅知识测验;其他模式为 0)
totalScorableQuestionsnumber计入分数的问题总数
maxScorenumber可获得的最高分数
matchedEndingIdstring 或 undefined根据分数显示给受访者的结束页面 ID
endingTalliesobject 或 undefined仅匹配测验:将每个结束页面 ID 映射到其计数

元数据

存储的回复还可能包含一个 metadata 对象,其中包含通过 URL 参数传递的隐藏字段。这可通过 Responses API 获取,但不包含在 webhook 负载中。

json
{
  "hiddenFields": {
    "utm_source": "google",
    "utm_campaign": "spring_sale",
    "user_id": "ext_12345"
  }
}

要访问 webhook 传递回复的元数据,请使用 responseId 获取:

bash
curl https://app.nueform.io/api/v1/forms/FORM_ID/responses/RESPONSE_ID \
  -H "Authorization: Bearer nf_your_api_key"

HTTP 头

每个 webhook 请求包含这些 HTTP 头:

头值
Content-Typeapplication/json
X-NueForm-Signature原始请求体的 HMAC-SHA256 十六进制摘要

有关如何验证签名,请参阅验证。

负载大小

Webhook 负载通常很小(低于 10 KB)。大小主要取决于问题数量和文本答案的长度。文件上传答案包含 URL(而非文件内容),因此不会显著增加负载大小。

后续步骤

  • 验证 --- 验证 webhook 签名
  • 测试 --- 在本地测试 webhook 负载
  • 事件 --- 事件类型和传递保证
最后更新:2026年10月8日