يُرسل كل طلب webhook من NueForm حمولة JSON في جسم الطلب. توثق هذه الصفحة مخطط الحمولة الكامل لكل نوع حدث.
الهيكل المشترك
تشترك جميع حمولات webhook في هذه الحقول ذات المستوى الأعلى:
| الحقل | النوع | الوصف |
|---|---|---|
event | string | نوع الحدث (مثل form.submitted) |
formId | string | المعرّف الفريد للنموذج |
formTitle | string | عنوان النموذج وقت الإرسال |
responseId | string | المعرّف الفريد للاستجابة |
answers | array | مصفوفة كائنات الإجابات |
respondent | object أو null | هوية المستجيب المسجّل عند اشتراط النموذج لتسجيل الدخول. null للإرسالات المجهولة. انظر هوية المستجيب. |
submittedAt | string | طابع وقت ISO 8601 لوقت إرسال الحدث |
حمولة form.submitted
هذه هي الحمولة المُرسلة عندما يُرسل المستجيب استجابة نموذج كاملة.
مثال كامل
{
"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 للنموذج. سلسلة سداسية عشرية من ٢٤ حرفاً.
formTitle --- string
العنوان المقروء للنموذج وقت إطلاق webhook. لاحظ أنه إذا أعدت تسمية النموذج لاحقاً، ستظل webhooks المُسلّمة سابقاً تحتوي على العنوان القديم.
responseId --- string
معرّف MongoDB ObjectId للاستجابة المخزنة. يمكنك استخدامه لجلب الاستجابة الكاملة عبر واجهة الاستجابات API أو كمفتاح تجنب تكرار لإزالة تكرار تسليمات webhook.
submittedAt --- string
طابع وقت ISO 8601 يشير إلى وقت إرسال webhook. يُنشأ وقت الإرسال وسيكون قريباً جداً من (لكن ليس بالضرورة مطابقاً لـ) حقل submittedAt في قاعدة البيانات.
respondent --- object أو null
هوية المستخدم المسجّل الذي أرسل الاستجابة، تُكشف فقط عندما يشترط النموذج تسجيل الدخول (requireLogin: true). تكون null لجميع الإرسالات المجهولة. انظر هوية المستجيب أدناه للحصول على المخطط الكامل والسلوك.
كائنات الإجابات
يمثل كل عنصر في مصفوفة answers إجابة سؤال واحد:
| الحقل | النوع | الوصف |
|---|---|---|
questionId | string | معرّف MongoDB ObjectId للسؤال |
value | any | إجابة المستجيب (يختلف التنسيق حسب نوع السؤال) |
label | string | في الإرسالات عبر الويب فقط. عنوان السؤال نصًا عاديًا، باللغة التي أجاب بها المستجيب. |
type | string | في الإرسالات عبر الويب فقط. نوع السؤال، مثل short_text أو matrix. |
subLabels | object | في الإرسالات عبر الويب فقط، للسؤال الذي له حقول فرعية، مثل معلومات الاتصال أو العنوان أو مجموعة أسئلة. تربط معرّف كل حقل فرعي بتسميته. |
valueLabels | object | في الإرسالات عبر الويب وعبر المكالمات الهاتفية، للسؤال الذي تأتي خياراته أو صفوفه أو أعمدته من متغيّر. عندها تحمل value قيم العناصر، وتعطي هذه الخريطة تسمية كل قيمة مختارة. وفي المصفوفة تكون المفاتيح row:<القيمة> وcolumn:<القيمة>. ولا تحمله إجابات القوائم الثابتة. |
أما إجابات المكالمات الهاتفية فتحمل questionId وvalue، ومعهما valueLabels للقائمة المأخوذة من متغيّر. وقد تحمل إجابات الويب أيضًا viewedAt وansweredAt: وقت عرض السؤال ووقت الإجابة عنه، كطوابع زمنية بتنسيق ISO 8601 من جهاز المستجيب. وقد تُضاف حقول أخرى مع الوقت، لذا تجاهل ما لا تستخدمه منها.
وتبدو إجابة الويب عن قائمة محمّلة من متغيّر هكذا:
{
"questionId": "507f1f77bcf86cd799439099",
"value": "siamese",
"label": "Which breed is your cat?",
"type": "dropdown",
"valueLabels": { "siamese": "Siamese" }
}
أما الإجابة نفسها إذا أُعطيت في مكالمة هاتفية فتصل دون label وtype.
قيم الإجابات حسب نوع السؤال
يختلف حقل value في كل كائن إجابة حسب نوع السؤال. إليك التنسيق لكل نوع:
مدخلات النص
| نوع السؤال | نوع القيمة | مثال |
|---|---|---|
short_text | string | "Jane Doe" |
long_text | string | "I really enjoyed the product..." |
email | string | "jane@example.com" |
phone | string | "+1 (555) 123-4567" |
number | number | 42 |
url | string | "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_no | boolean | true |
تحمل value معرّفات الخيارات لا تسمياتها: أي id كل خيار مختار ضمن choices الخاصة بالسؤال. والمعرّفات التي يُنشئها المنشئ هي بصيغة UUID. وتقبل واجهة API وخادم MCP أيضًا خيارًا بلا id، مثل { "label": "Search engine" }؛ وعندها تحمل value في إجابة الويب قيمة label لذلك الخيار بدلًا من المعرّف. يرسل multiple_choice وdropdown سلسلة نصية واحدة، أو مصفوفة سلاسل نصية عندما يكون allowMultiple بقيمة true. وخيارات الصور (layout: "blocks") هي أيضًا أسئلة multiple_choice.
إذا اختار المستجيب أخرى، يكون العنصر __other__: متبوعًا بالنص الذي كتبه، كما في المثال أعلاه. أما المكالمة الهاتفية فتحفظ إجابة «أخرى» بكلمات المتصل نفسه، دون البادئة.
لا تُرسل Webhooks تسميات القائمة الثابتة. لعرضها، ابحث عن كل معرّف ضمن choices الخاصة بالسؤال، والتي تُعيدها الحصول على نموذج؛ أما الخيار الذي لا يحمل id فتحمل value قيمة label الخاصة به مباشرةً. وعندما تأتي الخيارات من متغيّر، تحمل value قيم العناصر، وتعطي valueLabels الخاصة بالإجابة تسمياتها — راجع كائنات الإجابات.
أسئلة التقييم
| نوع السؤال | نوع القيمة | مثال | النطاق |
|---|---|---|---|
rating | number | 4 | ١ إلى steps (افتراضي ٥) |
opinion_scale | number | 7 | min إلى max |
nps | number | 9 | ٠ إلى ١٠ |
التاريخ والوقت
| نوع السؤال | نوع القيمة | مثال |
|---|---|---|
date | string | "2025-03-15" |
يطابق تنسيق سلسلة التاريخ خاصية dateFormat المُعدّة على السؤال (الافتراضي YYYY-MM-DD).
القانوني والبيانات
| نوع السؤال | نوع القيمة | مثال |
|---|---|---|
legal | boolean | true |
statement | string | "" (فارغ دائماً --- البيانات لا تجمع بيانات) |
الترتيب
| نوع السؤال | نوع القيمة | مثال |
|---|---|---|
ranking | array<string> | ["5d8f1b36-a9e2-4c07-b3d4-6e1a9f7c2b58", "c3a1e5f2-8b4d-4f6a-9e21-7d0b3c8a5f14", "71a4c9e0-3b5d-4f82-9c16-d2e8a0b7f345"] |
تحمل المصفوفة معرّفات الخيارات بالترتيب الذي اختاره المستجيب، من الأول إلى الأخير؛ وفي إجابة الويب، يظهر الخيار المحفوظ بلا id بقيمة label الخاصة به بدلًا من المعرّف. اربط المعرّفات بتسمياتها كما في أسئلة الاختيار.
المصفوفة
| نوع السؤال | نوع القيمة | مثال |
|---|---|---|
matrix | object | { "Speed": "Satisfied", "Price": "Neutral" } |
في المصفوفة ذات الصفوف والأعمدة الثابتة، يربط الكائن تسمية كل صف بتسمية العمود المُحدد. وعندما تأتي صفوفها أو أعمدتها من متغيّر، يربط قيم الصفوف بـقيم الأعمدة، وتكون التسميات التي رآها المستجيب في valueLabels الخاصة بالإجابة، تحت المفاتيح row:<القيمة> وcolumn:<القيمة>.
رفع الملفات
| نوع السؤال | نوع القيمة | مثال |
|---|---|---|
file_upload | string | "https://storage.nueform.io/uploads/abc123.pdf" |
القيمة هي عنوان URL للملف المرفوع في تخزين NueForm.
التوقيع والرسم
| نوع السؤال | نوع القيمة | مثال |
|---|---|---|
signature | string | "data:image/png;base64,iVBOR..." |
drawing | string | "data:image/png;base64,iVBOR..." |
كلاهما يعيد URI بيانات PNG مشفرة بـ base64 للصورة الملتقطة.
التسجيل
| نوع السؤال | نوع القيمة | مثال |
|---|---|---|
recording | string | "https://storage.nueform.io/recordings/abc123.webm" |
القيمة هي عنوان URL لملف التسجيل المرفوع.
الأسئلة المركبة
تُنتج أنواع الأسئلة المركبة (contact_info وaddress وquestion_group وmulti_question_page) عنصر إجابة واحدًا تحت questionId الخاص بالسؤال المركب نفسه. وتكون value فيه كائنًا مفاتيحه معرّفات الحقول الفرعية. تستخدم معلومات الاتصال والعنوان معرّفات مدمجة مثل first_name وzip_code، بينما تستخدم مجموعة الأسئلة أو صفحة الأسئلة المتعددة معرّف كل سؤال بداخلها. وتتبع قيمة كل حقل فرعي تنسيق نوع سؤاله. وتحمل إجابات الويب أيضًا subLabels، التي تربط معرّف كل حقل فرعي بتسميته.
مثلاً، يُنتج سؤال contact_info:
{
"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.
المخطط
{
"respondent": {
"id": "507f1f77bcf86cd799439016",
"name": "Jane Smith",
"email": "jane@example.com",
"auth_method": "sso"
}
}
| الحقل | النوع | الوصف |
|---|---|---|
id | string | معرّف المستخدم للمستجيب. |
name | string | الاسم المعروض في حساب المستجيب. |
email | string | عنوان البريد الإلكتروني في حساب المستجيب. |
auth_method | string | إما "sso" أو "login". "sso" تشير إلى أن المستجيب عضو في فريق النموذج عبر تسجيل الدخول الموحّد؛ "login" تشير إلى أي طريقة مصادقة أخرى مدعومة. |
متى يتم تعبئة respondent
تتم تعبئة respondent فقط عندما:
- يكون لدى النموذج
requireLoginمضبوطاً علىtrue، و - سجّل المُرسِل دخوله لأن النموذج اشترط ذلك قبل الإرسال.
عندما يكون 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، يمكنك استرجاعه عبر واجهة الاستجابات API باستخدام responseId من webhook.
يحتوي كائن quizResults على الهيكل التالي:
{
"formMode": "knowledge_quiz",
"score": 7,
"correctAnswers": 7,
"totalScorableQuestions": 10,
"maxScore": 10,
"matchedEndingId": "507f1f77bcf86cd799439099"
}
| الحقل | النوع | الوصف |
|---|---|---|
formMode | string | وضع الاختبار: knowledge_quiz أو lead_qualification أو match_quiz |
score | number | مجموع نقاط المستجيب |
correctAnswers | number | عدد الأسئلة المُجابة بشكل صحيح (اختبار المعرفة فقط؛ 0 للأوضاع الأخرى) |
totalScorableQuestions | number | إجمالي عدد الأسئلة التي تساهم في النتيجة |
maxScore | number | أقصى نتيجة ممكنة |
matchedEndingId | string أو undefined | معرّف شاشة النهاية المعروضة للمستجيب بناءً على نتيجته |
endingTallies | object أو undefined | اختبار المطابقة فقط: يربط كل معرّف شاشة نهاية بعدد التصويتات |
البيانات الوصفية
قد تتضمن الاستجابة المخزنة أيضاً كائن metadata يحتوي على حقول مخفية مُمررة عبر معلمات URL. هذا متاح عبر واجهة الاستجابات API لكنه غير مُضمّن في حمولة webhook.
{
"hiddenFields": {
"utm_source": "google",
"utm_campaign": "spring_sale",
"user_id": "ext_12345"
}
}
للوصول إلى البيانات الوصفية لاستجابة مُسلّمة عبر webhook، اجلبها باستخدام responseId:
curl https://app.nueform.io/api/v1/forms/FORM_ID/responses/RESPONSE_ID \
-H "Authorization: Bearer nf_your_api_key"
ترويسات HTTP
يتضمن كل طلب webhook هذه الترويسات HTTP:
| الترويسة | القيمة |
|---|---|
Content-Type | application/json |
X-NueForm-Signature | ملخص HMAC-SHA256 سداسي عشري لجسم الطلب الخام |
راجع التحقق لكيفية التحقق من صحة التوقيع.
حجم الحمولة
حمولات webhook عادة صغيرة (أقل من ١٠ كيلوبايت). يعتمد الحجم بشكل أساسي على عدد الأسئلة وطول إجابات النص. تحتوي إجابات رفع الملفات على عناوين URL (وليس محتويات الملفات)، لذا لا تزيد حجم الحمولة بشكل كبير.