تخطّي إلى المحتوى
التوقيع عبر API · بعلامتك

وقّع داخل تطبيقك وبعلامتك أنت، دون تحويل المستخدم لأي موقع خارجي

ادمج صفحة توقيع كاملة في منتجك، بشعارك وألوانك ونطاقك. تُصدِر جلسة توقيع قصيرة العمر من خادمك، ثم تضمّنها في إطار iframe أو تُعيد التوجيه إليها، وتستقبل الأحداث لحظيًا عبر postMessage وإشعارات الأحداث الآلية (Webhooks)، بينما يبقى المفتاح السرّي على خادمك وحده. وتجري خطوات التوقيع وتأكيد الهوية والتوقيع المؤهّل كلّها في مسار واحد لا يغادر تطبيقك.

تضمين بإطار أو إعادة توجيه نطاق توقيع خاص بك تأكيد هوية و QES في المسار
wthaiq:signed signing_session app.yourbrand.com تفعيل الحساب راجِع الاتفاقية ووقّعها لإتمام التسجيل مُضمَّن · بعلامتك وقّع هنا تأكيد التوقيع
نماذج التكامل

ثلاث طرق لدمج التوقيع، فاختر ما يناسب تطبيقك

الأساس واحد في النماذج الثلاثة: تُنشئ signature_request على خادمك، ثم تحصل على رابط توقيع للموقّع. يختلف النموذج في كيفية وصول المستخدم إلى ذلك الرابط.

1
hosted

الصفحة المستضافة

حوّل المستخدم إلى signing_url الذي يعود جاهزًا ضمن بيانات الموقّع. وهذه أسرع طريقة للإطلاق: صفحة توقيع كاملة تستضيفها «وثائق» على نطاقك المخصّص، دون أي برمجة للواجهة.

  • صفر كود في المتصفّح — رابط مباشر
  • يعمل على النطاق المخصّص sign.yourbrand.com
  • مثالي للروابط عبر البريد أو الرسائل
2
embedded / iframe

التضمين داخل التطبيق

أصدِر signing_session قصيرة العمر، ثم اعرضها داخل إطار iframe في صفحتك. يبقى المستخدم في مكانه تمامًا، وتتلقّى أحداث الجلسة لحظيًّا عبر postMessage.

  • أعلى معدّل إكمال دون مغادرة الصفحة
  • أحداث wthaiq:viewed / signed / declined
  • رمز عميل قصير العمر — لا مفتاح سرّي
3
redirect

إعادة التوجيه

حوّل المتصفّح إلى صفحة التوقيع، ثم أعِده تلقائيًا إلى success_url بعد التوقيع أو cancel_url عند الإلغاء. وهو حلٌّ وسط بين البساطة والتحكّم.

  • عودة مضمونة إلى مسار تطبيقك
  • مناسب لبيئات لا تسمح بالـiframe
  • يُعاد المرجع في متغيّر الرابط
مسارات العمل

الربط بثلاثة أشياء: معرّف المسار والمفتاح السرّي وسرّ التوقيع

اضبط مسار العمل مرّةً واحدة في لوحة المطوّرين: المستند، وطريقة التوقيع، وقناة الإرسال، ومدّة صلاحية الرابط. بعدها يرسل خادمك طلبًا قصيرًا يسمّي المسار والموقّعين، وتعود النتيجة إليه في إشعار حدثٍ آليّ موقَّع.

wf_…

معرّف مسار العمل المنشور في حسابك. يُرسَل في الحقل workflow_id، ومنه تؤخذ إعدادات الطلب كلّها.

sk_…

المفتاح السرّي. يُرسَل من خادمك وحده في الترويسة Authorization؛ فنقاط الجلسات لا تقبل المفتاح العامّ pk_.

whsec_…

سرّ توقيع الإشعارات. تتحقّق به من الترويسة Wthaiq-Signature في كل إشعار يصل إلى خادمك قبل أن تعتمد عليه.

أين يُبنى المسار؟ تُنشأ المسارات وتُنشَر من صفحة مسارات العمل في لوحة المطوّرين. وتعمل الجلسة بآخر إصدار منشور من المسار؛ فتعديلات المسودّة لا تمسّ طلباتك حتى تنشرها.

إنشاء جلسة من مسار عمل

الجلسة طلب توقيع يُنشأ بإعدادات مسار منشور، ومعرّفها هو معرّف طلب التوقيع نفسه sr_…؛ فتعمل معها نقاط signature_requests كما هي: الجلب والإلغاء والأحداث والتنزيل ومحضر الأدلّة. وهي غير جلسة التوقيع المضمَّنة signing_session المشروحة في قسم «جلسة التوقيع» أدناه.

POST /v1/sessions

يُنشئ طلب توقيع بإعدادات المسار المنشور ويرسله في الحال، ثم يعيد كائن الجلسة ومعه رابط التوقيع لكل موقّع.

المُعامِلالوصف
workflow_id
string مطلوب
معرّف مسار منشور في حسابك، وصيغته wf_….
signers
array مطلوب
من موقّع واحد إلى خمسة موقّعين. لكل موقّع الاسم name وهو مطلوب، ثم email أو phone بحسب قناة الإرسال. ويُقبل معها اختياريًّا type · fields · access_code.
vendor_data
string اختياري
مرجعك في نظامك، حتى 190 حرفًا. يُحفظ مع الجلسة ويعود في كائنها وفي الإشعارات، وتُصفّى به قائمة الجلسات.
template_id
string بحسب المسار
قالب الطلب، وصيغته tpl_ متبوعة برقم القالب. يُرسَل حين يكون مستند المسار «يُحدَّد مع كل طلب»، ويلزم إن لم يكن للمسار قالب افتراضي. ويُقبل بدلًا منه document_id لمستند نصّي في حسابك، ولا يُقبل الاثنان معًا ولا ملفّ PDF مرفوع.
title
fields
metadata
اختياري
عنوان الطلب، وقيم حقول القالب، وبياناتك الوصفية الحرّة، كما هي في نقطة طلبات التوقيع.
الكود السرّي. إن اشترطه المسار فأرسل لكل موقّع access_code من 4 إلى 32 حرفًا. يُحفظ الكود مجزَّأً ولا يُكتب في رسالة الدعوة، فسلّمه للموقّع بوسيلتك.
cURL Node Response
session.sh
curl -X POST https://wthaiq.com/api/v1/sessions \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5f3c9c2e-2b7a-4a1e-9c2f-1d3e4f5a6b7c" \
  -d '{
    "workflow_id": "wf_8f3a1c9e2b",
    "vendor_data": "ORD-1001",
    "signers": [
      {"name": "أحمد محمد", "email": "ahmed@example.com"}
    ]
  }'
server.js
// على الخادم فقط — المفتاح السرّي لا يغادر خادمك
const r = await fetch('https://wthaiq.com/api/v1/sessions', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.WTHAIQ_SECRET_KEY}`,
    'Wthaiq-Version': '2026-07-01',
    'Content-Type': 'application/json',
    'Idempotency-Key': order.id
  },
  body: JSON.stringify({
    workflow_id: process.env.WTHAIQ_WORKFLOW_ID,
    vendor_data: order.id,
    signers: [{ name: order.customerName, email: order.customerEmail }]
  })
});
const session = await r.json();

// احفظ session.id مع الطلب في نظامك؛ فالنتيجة تصل في الإشعار الموقَّع
201 Created · session
{
  "id": "sr_3n8Kd2Qa1V",
  "object": "session",
  "status": "sent",
  "workflow_id": "wf_8f3a1c9e2b",
  "workflow_version": 1,
  "vendor_data": "ORD-1001",
  "channel": "email",
  "signers": [
    {
      "id": "sgr_9fA2",
      "name": "أحمد محمد",
      "email": "ahmed@example.com",
      "phone": null,
      "status": "sent",
      "sign_url": "https://wthaiq.com/sign.php?token=uZ8.."
    }
  ],
  "sign_url": "https://wthaiq.com/sign.php?token=uZ8..",
  "created_at": 1754000000,
  "expires_at": 1754604800,
  "livemode": true,
  "cost": { "amount": 0, "currency": "EGP", "source": "plan" }
}

ما يجوز تغييره مع الطلب

إعدادات المسار هي الأصل، ويجوز لطلب بعينه أن يغيّر الحقول السبعة التالية وحدها. وما يرسله الطلب منها يسري على ذلك الطلب دون غيره، ولا يغيّر المسار.

الحقلالوصف
signature_method
string
طريقة التوقيع: simple توقيع موثّق بالرسم ورمز التحقّق، identity توقيع بعد تأكيد الهوية، token ختم بشهادة التوكن.
channel
string
قناة إيصال رابط التوقيع: email بالبريد الإلكتروني، whatsapp برسالة واتساب، link بلا رسالة، فيعود الرابط إلى خادمك لتسلّمه بنفسك.
cc
array
عناوين بريد تصلها نسخة من العقد بعد اكتمال التوقيع، حتى 20 عنوانًا. وتحلّ القائمة المرسَلة محلّ قائمة المسار.
require_id_attachment
boolean
إلزام الموقّع بإرفاق صورة هويته؛ فلا يكتمل توقيعه قبل إرفاقها.
expires_in
integer
مدّة صلاحية الرابط بالأيام، من 1 إلى 30.
language
string
لغة صفحة التوقيع ورسالة الدعوة: ar أو en.
return_url
string
رابط يعود إليه الموقّع بعد أن يوقّع أو يرفض. يبدأ بـ https:// ويكون على دومين مقبول في حسابك، ويحلّ محلّ رابط المسار في هذا الطلب. والقيمة الفارغة تلغي رابط المسار في هذا الطلب.
القناةما تشترطه وما تفعله
emailبريد لكل موقّع. تصله الدعوة ورمز التحقّق والتذكيرات بالبريد، وهي قناة كل مسار جديد ما لم تغيّرها.
whatsappرقم واتساب لكل موقّع بالصيغة الدولية، وتصله الدعوة ورمز التحقّق برسائل واتساب بلا تكلفة إضافية. وتُرفض القناة بمفتاح حيّ ما دامت غير مفعَّلة على المنصّة.
linkبريد أو رقم لكل موقّع، ليصله رمز التحقّق حين يفتح الرابط. لا تُرسَل دعوة ولا تذكيرات، وتعود الروابط كلها في الردّ. ومع مسار يوقّع أطرافه بالترتيب لا تقبل صفحة التوقيع طرفًا قبل أن يوقّع مَن قبله.
ما لا يُقبل في الطلب. تُضبط في المسار وحده: ordered · reminders · require_access_code. وتُرفض كذلك الحقول send · legal_level · require_identity · source · document، والحقلان method · require_identity داخل الموقّع، وتسمية مستند لمسار قالبه ثابت. ويعود الرفض بالرمز invalid_override واسم الحقل في param.
القيم الافتراضية. الحقل الذي لا يرسله الطلب يأخذ قيمته من المسار. وقيم المسار الأساسية، قبل أن تعدّلها أو تبدأ من قالب جاهز، هي: signature_method: simple · channel: email · expires_in: 7 · language: ar · require_id_attachment: false · cc: [].
الجلسة والنتيجة

ما يعود إلى خادمك: كائن الجلسة ثم الإشعار الموقَّع

يعيد ردّ الإنشاء كائن الجلسة في الحال، ثم تصل الأحداث إلى نقطة الاستقبال لديك بأسمائها المعهودة، ويحمل كلٌّ منها معرّف المسار ورقم إصداره ومرجعك.

الحقلالوصف
idمعرّف الجلسة، وهو معرّف طلب التوقيع نفسه sr_….
statusحالة الطلب: draft · sent · partially_signed · completed · declined · expired · canceled.
workflow_id
workflow_version
المسار الذي أُنشئت منه الجلسة، ورقم إصداره المنشور لحظة إنشائها.
vendor_dataمرجعك كما أرسلته، أو null.
channelالقناة التي أُرسل بها رابط التوقيع.
signers[]لكل موقّع: id · name · email · phone · status · sign_url.
sign_urlرابط التوقيع حين يكون الموقّع واحدًا. وقيمته null عند تعدّد الموقّعين؛ فخذ الرابط حينئذٍ من كل موقّع.
created_at
expires_at
وقت الإنشاء وموعد انتهاء صلاحية الرابط، بتوقيت unix.
costما خُصم من محفظتك عن هذا الطلب: المبلغ (amount) بعملة محفظتك (currency)، والمصدر (source): plan حين يُحتسب الإرسال من رصيد باقتك السنوي فلا يشمل المبلغ إلا تأكيد الهوية، و overage حين يُخصم الإرسال من المحفظة. وقيمة المبلغ 0 بمفتاح التجربة.
return_urlرابط العودة بعد التوقيع. يظهر الحقل حين يكون للطلب رابط عودة، ويغيب في غير ذلك.
trialقيمته true في طلب حيّ قديم أُرسل ضمن الطلبات المجانية التي كانت تُتاح قبل توثيق الحساب، ويغيب الحقل في غيره.
إشعار الطلب إشعار الموقّع قائمة الجلسات
signature_request.completed
{
  "id": "evt_2M8pQ",
  "object": "event",
  "type": "signature_request.completed",
  "created_at": 1754500000,
  "livemode": true,
  "data": {
    "object": {
      "id": "sr_3n8Kd2Qa1V",
      "object": "signature_request",
      "status": "completed",
      "reference": "WTQ-1A2B3C4D5E6F",
      "download_url": "https://wthaiq.com/api/v1/signature_requests/sr_3n8Kd2Qa1V/download",
      "workflow_id": "wf_8f3a1c9e2b",
      "workflow_version": 1,
      "vendor_data": "ORD-1001",
      "channel": "email"
    }
  }
}
signer.signed
{
  "id": "evt_2M8pP",
  "object": "event",
  "type": "signer.signed",
  "created_at": 1754499990,
  "livemode": true,
  "data": {
    "object": {
      "id": "sgr_9fA2",
      "object": "signer",
      "status": "signed",
      "signature_request": "sr_3n8Kd2Qa1V",
      "workflow_id": "wf_8f3a1c9e2b",
      "workflow_version": 1,
      "vendor_data": "ORD-1001"
    }
  }
}
list.sh
curl "https://wthaiq.com/api/v1/sessions?vendor_data=ORD-1001&limit=20" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"

# الاستجابة
{
  "object": "list",
  "data": [ { "id": "sr_3n8Kd2Qa1V", "object": "session", "status": "completed", "vendor_data": "ORD-1001" } ],
  "has_more": false,
  "next_cursor": null
}
حقول المسار في الإشعارات. أسماء الأحداث لا تتغيّر. تحمل أحداث signature_request.* كائن طلب التوقيع وفيه workflow_id · workflow_version · vendor_data · channel. وتحمل أحداث signer.* الحقول الثلاثة الأولى ومعها معرّف الطلب في signature_request. أمّا الطلب المنشأ بلا مسار فحمولته باقية كما هي.

جلب جلسة وتصفّح الجلسات

الإشعار هو الطريق الموصى به لمعرفة النتيجة. وتبقى النقطتان التاليتان للاستعلام عند الحاجة، ولمطابقة ما في نظامك بمرجعك.

GET /v1/sessions/{id}

يعيد كائن الجلسة بحالته الحالية. ويعيد 404 لطلب توقيع لم يُنشأ من مسار عمل.

GET /v1/sessions

يعيد الجلسات من الأحدث إلى الأقدم في وضع المفتاح نفسه، حيًّا كان أو تجربة. ويُصفّى بالمعاملات workflow_id · vendor_data · status، ويُقسَّم إلى صفحات بالمعاملين limit · starting_after؛ والصفحة 20 جلسة ما لم تحدّد غير ذلك، وأقصاها 100.

الأخطاء

تعود الأخطاء بالصيغة الموحّدة للواجهة، ويحمل الحقل param اسم الحقل الذي سبّب الخطأ.

الرمزمتى يعود
parameter_missing
400
غاب workflow_id أو signers، أو غاب template_id عن مسار يُحدَّد مستنده مع كل طلب ولا قالب افتراضي له.
workflow_not_found
404
معرّف المسار غير موجود في حسابك.
workflow_not_live
409
المسار لم يُنشَر بعد، أو مؤرشف، أو لم يُحدَّد قالبه الثابت.
invalid_override
400
حقل لا يُقبل تغييره من الطلب، أو قيمة غير صالحة لحقل يُقبل تغييره.
invalid_signer
400
بيانات موقّع ناقصة أو غير صالحة: الاسم، أو البريد، أو الرقم، أو ما تشترطه القناة، أو الكود السرّي، أو زاد الموقّعون على خمسة.
invalid_request
400
قيمة vendor_data غير صالحة، أو القالب أو المستند المسمّى غير موجود.
channel_unavailable
400
طُلبت قناة واتساب بمفتاح حيّ وهي غير مفعَّلة على المنصّة.
insufficient_balance
402
الرصيد لا يكفي تكلفة الطلب. يُفحص قبل الإنشاء، فلا يبقى طلب ولا خصم.
delivery_failed
502
تعذّر إيصال الدعوة إلى أيّ موقّع؛ فتُعاد التكلفة إلى الرصيد ويبقى الطلب مسودّة.
domain_not_accepted
400
دومين الرابط المرسَل في return_url غير مقبول في حسابك. أضِف الدومين من صفحة الدومينات في لوحة المطوّرين وانتظر قبوله.
plan_required
402
طلب حيّ من حساب بلا باقة مدفوعة سارية، ووضع التجربة متاح دائمًا. ويحمل الخطأ رابط صفحة الباقات في الحقل upgrade_url.
plan_expired
402
انتهت سنة الاشتراك دون تجديد، فتوقّف الإرسال الحيّ حتى تُجدَّد الباقة. ويحمل الخطأ رابط صفحة الباقات في الحقل upgrade_url.
kyb_required
403
طلب حيّ قبل اعتماد توثيق الشركة. ويحمل الخطأ رابط صفحة «توثيق الشركة» في لوحة المطوّرين في الحقل verify_url.
forbidden
403
استُعمل مفتاح عامّ pk_، أو مفتاح للقراءة فقط في طلب إنشاء.

التكلفة

يُحتسب كل موقّع في الجلسة الحيّة إرسالًا من رصيد باقتك السنوي، والحدّ الأقصى خمسة موقّعين. وبعد نفاد الرصيد يُخصم كل إرسال زائد من المحفظة بسعر الزيادة في باقتك، ويُخصم من المحفظة $1.50 عن كل موقّع حين تكون طريقة التوقيع identity. ويعود ما خُصم من المحفظة في الحقل cost، ومصدره في cost.source.

وضع التجربة

بمفتاح التجربة sk_test_ لا يُخصم شيء، وتُتاح الخصائص كلها عدا الدومين الخاص. تصل الدعوة بالبريد بعلامة «تجربة» ولا تُرسَل نسخ، ولا تُرسَل رسائل واتساب بل تُسجَّل في أحداث الطلب، ويُحاكى تأكيد الهوية دون جلسة حقيقية. ويجب أن يكون بريد الموقّع لحسابك أو لأحد أعضاء فريقك، ويعود رابط التوقيع في الردّ لتجرّبه بنفسك. والحدّ اليومي 20 طلبًا و50 رسالة بريد، وفي الطلب 5 موقّعين على الأكثر.

منع التكرار

أرسل الترويسة Idempotency-Key مع طلب الإنشاء. فإذا أُعيد الطلب بالمفتاح نفسه خلال 24 ساعة عادت الجلسة نفسها مع الترويسة Idempotent-Replayed: true، فلا تُنشأ جلسة ثانية ولا يُخصم مرّتين.

المفاتيح المقبولة

نقاط الجلسات للمفتاح السرّي وحده. المفتاح العامّ pk_ يُرفض بالرمز 403، ومفتاح القراءة فقط يجلب الجلسات ولا يُنشئها.

رابط العودة بعد التوقيع

اضبط رابط العودة في المسار، أو أرسله مع الطلب في الحقل return_url. بعد أن يوقّع الموقّع أو يرفض يظهر له زرّ العودة، ثم يُحوَّل إلى رابطك ومعه session_id · signer_id · status بقيمة completed أو declined. واعتمد النتيجة من الإشعار الموقَّع أو من جلب الجلسة، لا من العودة.

التوقيع بالترتيب

حين يوقّع أطراف المسار بالترتيب يُدعى كل طرف بعد توقيع سابقه، ويصلك الحدث signer.sent عند حلول دوره. ومع القناة link تعود الروابط كلها في ردّ الإنشاء، ولا تقبل صفحة التوقيع طرفًا قبل أن يوقّع مَن قبله.

قناة رمز التحقّق

يصل رمز التحقّق بقناة الطلب وحدها: بالبريد مع email، وبواتساب مع whatsapp. ويصل بالبريد إن لم يكن للموقّع رقم، أو لم تكن رموز واتساب مفعَّلة على المنصّة. ومع link يصل إلى بريد الموقّع إن وُجد، وإلا فإلى رقمه. وقناة واتساب بلا تكلفة إضافية.

الوضع الحيّ وتوثيق الشركة

مفتاح التجربة مجاني في كل الباقات بحدّ يومي، ولا يُعتدّ بطلباته قانونًا. والطلب الحيّ يتطلّب باقة مدفوعة سارية وشركة موثّقة: بلا باقة يعود الخطأ plan_required بالرمز 402، وبعد انتهاء سنة الاشتراك plan_expired بالرمز 402، وقبل اعتماد توثيق الشركة kyb_required بالرمز 403. وتُوثَّق الشركة من صفحة «توثيق الشركة» في لوحة المطوّرين: تأكيد هوية ممثّلها، ثم مراجعة مستنداتها.

جلسة التوقيع

توليد جلسة توقيع قصيرة العمر

لا تُرسِل مفتاحك السرّي إلى المتصفّح أبدًا، بل يستدعي خادمك نقطة الاتصال هذه ليُصدِر رمز جلسة مؤقّتًا خاصًّا بموقّع واحد، يمكن إرساله إلى الواجهة بأمان.

POST /v1/signers/{id}/signing_session

يُصدِر رابط توقيع مُضمَّنًا صالحًا 30 دقيقة لموقّع محدّد، ضمن نمط التوقيع بعلامتك التجارية.

المُعامِلالوصف
return_url
string اختياري
رابط https كامل على دومين مقبول في حسابك، يُعاد إليه الموقّع بعد إتمام التوقيع، ومتاح في باقة «الأعمال» فأعلى. وصلاحية الجلسة ثابتة: 30 دقيقة.
لماذا جلسة قصيرة العمر بدل المفتاح السرّي؟ المفتاح sk_ يملك صلاحية كاملة على حسابك: إنشاء الطلبات، وتنزيل المستندات الموقّعة، وإدارة إشعارات الأحداث الآلية. ولو تسرّب عبر المتصفّح لتمكّن أي طرف من التحكّم فيه. أمّا رمز الجلسة فمقيّد بموقّع واحد، وبصلاحية «التوقيع» وحدها، ولمدّة دقائق معدودة، وعلى نطاقات محدّدة؛ فحتى لو التُقِط لا يفتح إلا ما أُصدِر من أجله، ثم تنتهي صلاحيته.
cURL Node Response
signing_session.sh
curl -X POST https://wthaiq.com/api/v1/signers/sgr_9fA2/signing_session \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01" \
  -H "Content-Type: application/json" \
  -d '{ "return_url": "https://app.acme-pay.com/signed" }'
server.js
// على الخادم فقط — المفتاح السرّي لا يغادر خادمك
const r = await fetch('https://wthaiq.com/api/v1/signers/sgr_9fA2/signing_session', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.WTHAIQ_SECRET_KEY}`,
    'Wthaiq-Version': '2026-07-01',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ return_url: 'https://app.acme-pay.com/signed' })
});
const session = await r.json();

// أرسِل هذا فقط إلى المتصفّح — لا شيء غيره
res.json({ signing_url: session.signing_url });
200 OK · signing_session
{
  "object": "signing_session",
  "signer": "sgr_9fA2",
  "signing_url": "https://wthaiq.com/embed/sign/9aF2xQ7bV3..",
  "expires_at": 1754001800
}
White-label

التخصيص الكامل للعلامة

صفحة التوقيع لك بالكامل. تُضبط إعدادات العلامة مرّةً واحدة على مستوى الحساب من صفحة «الهوية البصرية» في لوحة المطوّرين، وتُتاح في باقة «الأعمال» وما فوقها، وتُطبَّق تلقائيًّا على كل طلب توقيع تنشئه عبر الواجهة البرمجية؛ فلا يحمل جسم الطلب إعدادات للعلامة.

account-branding
{
  "brand_name": "Acme Pay",
  "logo_url": "https://cdn.acme-pay.com/logo.svg",
  "brand_color": "#0B5FFF",
  "custom_domain": "sign.acme-pay.com",
  "from_email": "sign@acme-pay.com",
  "hide_powered": true,
  "sign_welcome_ar": "مرحبًا بك في Acme Pay. راجع العقد ثم وقّعه.",
  "sign_welcome_en": "Welcome to Acme Pay. Review the contract, then sign.",
  "sign_button_color": "#0B5FFF"
}
الحقلالوصف
brand_nameاسم علامتك الظاهر في صفحة التوقيع، وهو اسم المُرسِل في رسائل الدعوة والتذكير بعد التحقّق من نطاقك.
logo_urlشعارك الذي يظهر أعلى صفحة التوقيع. ويُفضَّل بصيغة SVG أو PNG بخلفية شفّافة.
brand_colorاللون الأساسي لعلامتك بصيغة HEX، ويُطبَّق على الأزرار والروابط ومؤشّرات التقدّم.
custom_domainنطاق التوقيع المخصّص، مثل sign.acme-pay.com. ويُفعَّل النطاق الخاص بالتواصل مع فريقنا.
from_emailعنوان المُرسِل على نطاقك، بعد ضبط سجلّات SPF و DKIM لضمان وصول الرسائل.
hide_poweredعند تفعيله تُخفى عبارة «عبر منصّة وثائق» من صفحة التوقيع في طلبات واجهة الربط. وشهادة التوقيع وصفحة التحقّق العامّة تذكران وثائق دائمًا.
sign_welcome_ar
sign_welcome_en
جملة ترحيب تظهر للموقّع أعلى صفحة التوقيع بلغة الصفحة، نصًّا عاديًّا حتى 240 حرفًا.
sign_button_colorلون الأزرار الأساسية في صفحة التوقيع بصيغة HEX. إن غاب استُعمل لون العلامة، ولا يُقبل لون فاتح لأن نصّ الزرّ أبيض.
النطاق المخصّص يجعل شريط العنوان نفسه يعرض sign.acme-pay.com بدلًا من نطاق «وثائق»، فلا يرى المستخدم أي إشارة إلى مزوّد خارجي في أي مرحلة من مراحل التوقيع.
التضمين

التضمين في صفحتك عبر الإطار وأحداث المتصفّح

افتح الرابط signing_url الناتج عن الجلسة داخل إطار iframe، ثم استمع إلى أحداث النافذة عبر postMessage لتحديث واجهتك لحظيًا.

embed.html
<iframe
  id="wthaiq-frame"
  src="https://sign.acme-pay.com/embed/sign/9aF2xQ7bV3.."
  allow="camera; microphone"
  style="width:100%;height:760px;border:0;border-radius:16px">
</iframe>

<!-- allow: camera/microphone مطلوبة لخطوة تأكيد الهوية داخل الإطار -->
listen.js
window.addEventListener('message', function (e) {
  // تحقّق من مصدر الرسالة دائمًا قبل الوثوق بها
  if (e.origin !== 'https://sign.acme-pay.com') return;

  const evt = e.data;
  switch (evt.type) {
    case 'wthaiq:viewed':
      // فتح الموقّع المستند
      console.log('viewed', evt.signer);
      break;
    case 'wthaiq:signed':
      // اكتمل التوقيع — أغلِق الإطار وابدأ التفعيل
      onSigned(evt.signature_request);
      break;
    case 'wthaiq:declined':
      // رفض الموقّع — سجّل السبب وأعِد التوجيه
      onDeclined(evt.reason);
      break;
  }
});
wthaiq:viewed

يُطلَق عندما يفتح الموقّع المستند لأول مرة داخل الإطار، ويفيد في تتبّع بداية مسار التوقيع.

wthaiq:signed

يُطلَق فور إتمام التوقيع بنجاح، ويحمل signature_request و signer.

wthaiq:declined

يُطلَق عندما يرفض الموقّع التوقيع أو يتعذّر إتمامه، ويتضمّن الحقل reason.

أحداث المتصفّح مقابل إشعارات الأحداث الآلية. أحداث postMessage مثالية لتحديث الواجهة فورًا، لكنها ليست المرجع المعتمد، إذ قد يُغلق المستخدم التبويب قبل وصولها. لذلك عوِّل دائمًا على إشعار الحدث signature_request.completed الذي يصل إلى خادمك، بوصفه الإشارة النهائية الموثوقة قبل تنفيذ أي إجراء حسّاس.

إعادة التوجيه بدل التضمين

إن لم يناسبك الـiframe، فأصدِر الجلسة بنمط redirect مع success_url و cancel_url، ثم حوّل المتصفّح إلى signing_url. تعيد «وثائق» المستخدم إلى مسارك تلقائيًا مع المرجع في متغيّر الرابط.

بعد أن يوقّع المستخدم يُحوَّل إلى success_url، وإن رفض التوقيع فإلى cancel_url، ويُضاف إلى الرابط session_id و signer_id و status، ويُستبدل {signature_request} في الرابط بمعرّف الطلب. والرابطان https على دومين مقبول في حسابك، واعتمد النتيجة من الإشعار الموقَّع لا من العودة.

redirect.sh
curl -X POST https://wthaiq.com/api/v1/signers/sgr_9fA2/signing_session \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "redirect",
    "success_url": "https://app.acme-pay.com/onboarding/done?sr={signature_request}",
    "cancel_url": "https://app.acme-pay.com/onboarding/canceled"
  }'
الهوية والتوقيع المؤهّل

تأكيد الهوية و QES في تدفّق واحد

لا يحتاج المستخدم إلى مغادرة إطارك ليؤكّد هويته أو ليوقّع بشهادة مؤهّلة، إذ تظهر الخطوتان مُضمَّنتين قبل التوقيع مباشرة. وفيما يلي ما يراه المستخدم في كلٍّ منهما.

AES

تأكيد الهوية قبل التوقيع

عند تفعيل require_identity للموقّع، يعرض الإطار خطوة تحقّق كاملة قبل فتح صفحة التوقيع، ويُربط قرار التحقّق بالتوقيع نفسه.

ما يراه المستخدم
  • تصوير المستند الرسمييطلب الإطار تصوير بطاقة الهوية أو جواز السفر بالكاميرا مباشرةً داخل صفحتك.
  • مطابقة وجه حيّةيُطلب من المستخدم تحريك وجهه أمام الكاميرا للتأكّد من أنه شخص حقيقي حاضر، ثم يُطابَق وجهه مع صورة المستند.
  • «جارٍ التحقّق» ثم اعتماديظهر مؤشّر المعالجة ثم علامة نجاح خضراء، وتصبح حالة الموقّع identity_verified.
  • فتح صفحة التوقيعبعد الاعتماد فقط تُتاح منطقة التوقيع، فيوقّع المستخدم وقد ارتبط توقيعه بهوية مؤكّدة.
QES · token agent

التوقيع المؤهّل بالتوكن

للتوقيع المؤهّل (method: "token")، يجري التوقيع بالشهادة المحفوظة في التوكن عبر وكيل محلّي يعمل في جهاز المستخدم على العنوان 127.0.0.1:8899 دون أن يغادر المفتاح الخاص التوكن إطلاقًا (توقيع PAdES مؤجّل ومنفصل).

ما يراه المستخدم
  • اكتشاف الوكيل والتوكنتتحقّق الصفحة من أن الوكيل المحلّي يعمل وأن التوكن موصول، ثم تعرض «تمّ اكتشاف التوكن».
  • تجهيز التوقيع على الخادميحسب الخادم signedAttributes (بصمة SHA-256 للمستند)، ثم يرسل البصمة وحدها دون استخدام أي مفتاح خاص.
  • إدخال رمز PIN على الجهازيطلب الوكيل رمز التوكن، فيُدخله المستخدم ليأذن بعملية توقيع واحدة على الجهاز.
  • التوقيع محليًا ثم دمج CMSيوقّع التوكن البصمة ويعيد بنية CMS، فيدمجها الخادم في المستند ويستكمل صيغة PAdES حتى مستوى LTA.
qes-deferred.js
// 1) الخادم يجهّز signedAttributes (هاش المستند) — لا مفتاح خاص
const prep = await signingPage.prepareTokenSignature();
// prep.digest = SHA-256 لـ signedAttributes (ESS signingCertificateV2)

// 2) داخل المتصفّح: الوكيل المحلّي يوقّع على الجهاز
const signed = await fetch('https://127.0.0.1:8899/sign', {
  method: 'POST',
  body: JSON.stringify({ digest: prep.digest, alg: 'SHA256withRSA' })
}).then(r => r.json());
// المفتاح لا يغادر التوكن؛ يعيد الوكيل بنية CMS (adbe.pkcs7.detached)

// 3) الخادم يدمج CMS في المستند ويُنهي PAdES (LT/LTA)
await signingPage.completeTokenSignature({ cms: signed.cms });
يوضّح المقطع أعلاه ما تُجريه صفحة التوقيع بنفسها داخل الإطار؛ فلا تستدعي شيئًا منه من خادمك. تظهر الخطوتان داخل الإطار بعلامتك ولغتك. راجِع صفحة الحجّية للاطلاع على تفاصيل مستويات SES / AES / QES وتدرّج صيغ PAdES من B إلى LTA.
المسار الكامل

من الطلب إلى المستند الموقّع — خطوة بخطوة

مسار تضمين كامل: أنشئ الطلب على خادمك، ثم ضمِّن التوقيع، وانتظر إشارة الاكتمال الموثوقة، وأخيرًا نزّل المستند المختوم.

  1. أنشئ طلب توقيع مُضمَّن

    على خادمك، أنشئ signature_request مع موقّعيه ومصدره ومستواه القانوني.

    POST /v1/signature_requests
  2. احصل على رابط التوقيع

    استخرج signing_url من بيانات الموقّع، أو أصدِر signing_session قصيرة العمر للتضمين.

    signers[0].signing_url
  3. ضمِّن في صفحتك

    افتح الرابط داخل iframe واستمع إلى أحداث postMessage لتحديث الواجهة.

  4. يُكمل المستخدم التوقيع

    يؤكّد هويته (AES) عند الحاجة، ثم يوقّع داخل إطارك دون أن يغادر تطبيقك.

  5. استقبل الإشعار الموثوق

    يتلقّى خادمك حدث الاكتمال، وهو الإشارة النهائية لبدء إجراءات ما بعد التوقيع.

    signature_request.completed
  6. نزّل المستند المختوم

    اطلب نسخة PDF النهائية بعد اكتمال الطلب، أمّا دليلها التشفيري المستقل فهو محضر الأدلّة المختوم (Ed25519 + ختم زمني RFC 3161).

    GET /v1/signature_requests/{id}/download
1 · إنشاء 5 · Webhook 6 · تنزيل
create.sh
curl -X POST https://wthaiq.com/api/v1/signature_requests \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5f3c9c2e-2b7a-4a1e-9c2f-1d3e4f5a6b7c" \
  -d '{
    "title": "اتفاقية تاجر — Acme Pay",
    "source": {"type":"template","template_id":"tpl_merchant_agreement"},
    "legal_level": "aes",
    "signers": [
      {"name":"سلمى حسن","email":"salma@example.com","type":"individual",
       "method":"draw","require_identity":true}
    ],
    "metadata": {"merchant_id":"M-88213"}
  }'
webhook.json
{
  "id": "evt_2M8pQ",
  "object": "event",
  "type": "signature_request.completed",
  "created_at": 1754500000,
  "livemode": true,
  "data": {
    "object": {
      "id": "sr_3n8Kd2Qa1V",
      "object": "signature_request",
      "status": "completed",
      "reference": "WTQ-1A2B3C4D5E6F",
      "download_url": "https://wthaiq.com/api/v1/signature_requests/sr_3n8Kd2Qa1V/download"
    }
  }
}
download.sh
# متاح فقط بعد أن تصبح الحالة completed
curl https://wthaiq.com/api/v1/signature_requests/sr_3n8Kd2Qa1V/download \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Wthaiq-Version: 2026-07-01"

# الناتج: روابط العقد النهائي (JSON) · الدليل التشفيري المستقل: محضر الأدلّة عبر GET /v1/signature_requests/{id}/evidence
الأمان

قواعد أمان التضمين

التضمين آمن ما دمت تفصل بين ما يبقى على الخادم وما يصل إلى المتصفّح.

لا تُرسِل sk_ إلى المتصفّح أبدًا

يبقى المفتاح السرّي على الخادم حصرًا، ولا يرى المتصفّح إلا رابط التوقيع ورمز الجلسة قصير العمر.

عمر رمز قصير (TTL)

تنتهي صلاحية رابط الجلسة بعد 30 دقيقة من إنشائه، فالرابط المنتهي لا أثر له حتى لو التُقِط؛ فأنشئ الجلسة لحظة حاجة الموقّع إليها.

قائمة نطاقات مسموح بها

حدّد allowed_origins بنطاقاتك وحدها، فتُرفض أي محاولة لتضمين الجلسة من مصدر خارج القائمة.

تحقّق من الأحداث على الخادم

لا تنفّذ أي إجراء حسّاس بناءً على postMessage وحده، بل عوِّل على الإشعار الآلي الموقَّع بـwhsec_ بوصفه المرجع المعتمد.

أسئلة شائعة

أسئلة المطوّرين حول التضمين

هل يرى المستخدم أي إشارة إلى «وثائق» أثناء التوقيع؟

لا، إن فعّلت White-label الكامل. تظهر صفحة التوقيع بشعارك وألوانك وعلى نطاقك المخصّص sign.yourbrand.com، وتُرسل رسائل البريد باسم علامتك، وتُزال عبارة «مدعوم من وثائق» عند ضبط hide_powered: true. يبقى المستخدم داخل تجربتك من البداية للنهاية.

لماذا أسكّ signing_session بدل تمرير المفتاح السرّي؟

لأن sk_ يملك صلاحية كاملة على حسابك، ولا يجوز أن يصل إلى المتصفّح إطلاقًا. رمز الجلسة قصير العمر مقيّد بموقّع واحد وبصلاحية التوقيع فقط ولنطاقات محدّدة ولدقائق معدودة — فحتى لو التُقِط، لا يفتح إلا ما سُكّ لأجله ثم ينتهي تلقائيًا.

ما الفرق بين أحداث postMessage والـWebhooks؟

أحداث المتصفّح مثل wthaiq:signed لتحديث الواجهة لحظيًا، لكنها قد لا تصل إن أغلق المستخدم التبويب. الـWebhook مثل signature_request.completed يصل إلى خادمك على نحوٍ موثوق وموقّع بـwhsec_، وهو مصدر الحقيقة الذي تبني عليه أي إجراء حسّاس مثل التفعيل.

كيف يعمل التوقيع المؤهّل QES داخل الإطار؟

عبر وكيل توقيع محلّي على جهاز المستخدم عند 127.0.0.1:8899. يجهّز الخادم بصمة signedAttributes ويرسل الهاش فقط، فيُدخل المستخدم رمز التوكن ويوقّع الجهاز محليًّا — المفتاح الخاص لا يغادر التوكن — ثم يُدمج CMS في المستند لإكمال PAdES حتى LTA. هذا هو التوقيع المؤجّل/المُجزّأ.

ماذا لو لم تسمح بيئتنا باستخدام الـiframe؟

استخدم نمط redirect: اسكّ الجلسة مع success_url و cancel_url، ثم حوّل المتصفّح إلى signing_url. تعيد «وثائق» المستخدم إلى مسارك تلقائيًا مع المرجع في الرابط. أو استخدم الصفحة المستضافة مباشرة عبر signing_url على نطاقك المخصّص.

وقّع داخل تطبيقك وبعلامتك أنت.

ابدأ بجلسة توقيع واحدة خلال دقائق، ثم ضمِّن تجربة توقيع كاملة بعلامتك ونطاقك دون تحويل أي مستخدم إلى موقع خارجي.