مكتبات «وثائق» الرسمية: مفتوحة المصدر، بأنواع مضمّنة (typed)، ومصمّمة لتجعل التكامل مسألة دقائق. ثبّت الحزمة بأمر واحد، هيّئ العميل بمفتاحك، وأنشئ أول طلب توقيع دون كتابة طبقة HTTP يدويًا. تتكفّل المكتبة بإعادة المحاولة الآمنة، والترقيم عبر المؤشّر، وتثبيت إصدار الـAPI، والتحقق من توقيع الـWebhooks.
تتشارك جميع المكتبات نفس واجهة الموارد وأسماء العمليات، فما تتعلّمه في لغة ينطبق على الباقي. Node.js وPython وPHP هي مكتبات الفئة الأولى (tier-1) بأمثلة كاملة، وتتوفّر إلى جانبها Go وRuby و.NET.
TypeScript جاهزة مع تعريفات أنواع كاملة، وتعمل على Node و بيئات الحوسبة الطرفية.
npm i @wthaiq/nodeimport Wthaiq from '@wthaiq/node';
const wt = new Wthaiq('sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
const sr = await wt.signatureRequests.create({
title: 'عقد عمل',
source: { type: 'template', template_id: 'tpl_employment' },
legal_level: 'aes',
signers: [{ name: 'أحمد محمد', email: 'ahmed@example.com',
method: 'draw', require_identity: true }]
});
console.log(sr.id, sr.status); // sr_3n8Kd2Qa1V sentتعريفات أنواع عبر type hints وملفات stubs، وتوافق مع async عند الحاجة.
pip install wthaiqimport wthaiq
wt = wthaiq.Client('sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx')
sr = wt.signature_requests.create(
title='عقد عمل',
source={'type': 'template', 'template_id': 'tpl_employment'},
legal_level='aes',
signers=[{'name': 'أحمد محمد', 'email': 'ahmed@example.com',
'method': 'draw', 'require_identity': True}],
)
print(sr.id, sr.status) # sr_3n8Kd2Qa1V sentمتوافقة مع PSR وتعمل مع Laravel وSymfony وأي مشروع Composer، بأنواع صارمة.
composer require wthaiq/wthaiq-php$wt = new \Wthaiq\Client('sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx');
$sr = $wt->signatureRequests->create([
'title' => 'عقد عمل',
'source' => ['type' => 'template', 'template_id' => 'tpl_employment'],
'legal_level' => 'aes',
'signers' => [[
'name' => 'أحمد محمد', 'email' => 'ahmed@example.com',
'method' => 'draw', 'require_identity' => true,
]],
]);
echo $sr->id; // sr_3n8Kd2Qa1Vلست بحاجة إلى إعادة بناء منطق الشبكة والأمان. تُنفّذ كل مكتبة القدرات التالية بالطريقة نفسها، فتحصل على تجربة متّسقة عبر مشاريعك.
عند أخطاء الشبكة أو الردود العابرة (429/5xx) تُعيد المكتبة المحاولة بتراجع أُسّي، وترفق تلقائيًا مفتاح Idempotency-Key مع كل طلب POST حتى لا يتكرّر أي إنشاء.
مرِّر على آلاف السجلات دون إدارة المؤشّرات يدويًا. يجلب المُكرِّر الصفحات التالية تلقائيًا عبر starting_after اعتمادًا على next_cursor وhas_more.
دالّة مساعدة جاهزة (constructEvent) تتحقق من ترويسة Wthaiq-Signature بمقارنة ثابتة الزمن وتفرض هامش زمن 300 ثانية، ثم تُعيد كائن الحدث مُتحقَّقًا منه.
تُترجَم أخطاء الـAPI إلى استثناءات مُصنَّفة تطابق مغلّف الأخطاء: AuthenticationError وInvalidRequestError وRateLimitError وغيرها، مع code وparam وrequest_id.
تُرسل كل مكتبة ترويسة Wthaiq-Version: 2026-07-01 مثبَّتة مع كل طلب، فلا تتأثّر تكاملاتك بأي تغييرات لاحقة. يمكنك تجاوز الإصدار لكل عميل أو لكل طلب.
اضبط مهلة الاتصال والقراءة، وعدد مرّات إعادة المحاولة، والـHTTP client المستخدَم (مثل proxy مؤسسي) لكل عميل، بما يلائم بيئتك ومتطلّبات موثوقيتك.
اختر لغتك، وانسخ المثال مباشرة: إنشاء طلب توقيع، والتكرار عبر القوائم بترقيم تلقائي، والتحقق من توقيع الـWebhook قبل المعالجة.
import Wthaiq from '@wthaiq/node';
import { randomUUID } from 'node:crypto';
const wt = new Wthaiq(process.env.WTHAIQ_API_KEY);
const sr = await wt.signatureRequests.create({
title: 'عقد عمل — أحمد م.',
source: { type: 'template', template_id: 'tpl_employment' },
legal_level: 'aes',
ordered: true,
signers: [{
name: 'أحمد محمد',
email: 'ahmed@example.com',
type: 'individual',
method: 'draw',
require_identity: true,
fields: { job_title: 'مهندس برمجيات', salary: '25000' }
}],
reminders: { enabled: true, interval_hours: 48, max: 3 },
metadata: { order_id: 'A-1024' }
}, { idempotencyKey: randomUUID() });
console.log(sr.id, sr.status); // sr_3n8Kd2Qa1V sent// المُكرِّر يجلب الصفحات التالية تلقائيًا عبر المؤشّر
for await (const sr of wt.signatureRequests.list({ status: 'completed', limit: 100 })) {
console.log(sr.id, sr.reference);
}import express from 'express';
const app = express();
// مرِّر الجسم الخام (raw) للتحقق من التوقيع
app.post('/hooks/wthaiq', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['wthaiq-signature'];
let event;
try {
event = wt.webhooks.constructEvent(req.body, sig, process.env.WTHAIQ_WEBHOOK_SECRET);
} catch (err) {
return res.status(400).send(`signature check failed: ${err.message}`);
}
if (event.type === 'signature_request.completed') {
const sr = event.data.object; // كائن signature_request
// فعّل الحساب أو خزّن الوثيقة الموقّعة (نفّذ العمل الثقيل لاحقًا)
}
res.json({ received: true });
});import os, uuid, wthaiq
wt = wthaiq.Client(os.environ['WTHAIQ_API_KEY'])
sr = wt.signature_requests.create(
title='عقد عمل — أحمد م.',
source={'type': 'template', 'template_id': 'tpl_employment'},
legal_level='aes',
ordered=True,
signers=[{
'name': 'أحمد محمد',
'email': 'ahmed@example.com',
'type': 'individual',
'method': 'draw',
'require_identity': True,
'fields': {'job_title': 'مهندس برمجيات', 'salary': '25000'},
}],
reminders={'enabled': True, 'interval_hours': 48, 'max': 3},
metadata={'order_id': 'A-1024'},
idempotency_key=str(uuid.uuid4()),
)
print(sr.id, sr.status) # sr_3n8Kd2Qa1V sent# auto_paging_iter يتنقّل عبر كل الصفحات تلقائيًا
for sr in wt.signature_requests.list(status='completed', limit=100).auto_paging_iter():
print(sr.id, sr.reference)import os, wthaiq
from flask import Flask, request
app = Flask(__name__)
endpoint_secret = os.environ['WTHAIQ_WEBHOOK_SECRET']
@app.post('/hooks/wthaiq')
def handle():
payload = request.get_data()
sig = request.headers.get('Wthaiq-Signature')
try:
event = wthaiq.Webhook.construct_event(payload, sig, endpoint_secret)
except wthaiq.error.SignatureVerificationError:
return 'invalid signature', 400
if event.type == 'signature_request.completed':
sr = event.data.object # كائن signature_request
# فعّل الحساب أو خزّن الوثيقة الموقّعة
return {'received': True}require 'vendor/autoload.php';
$wt = new \Wthaiq\Client(getenv('WTHAIQ_API_KEY'));
$sr = $wt->signatureRequests->create([
'title' => 'عقد عمل — أحمد م.',
'source' => ['type' => 'template', 'template_id' => 'tpl_employment'],
'legal_level' => 'aes',
'ordered' => true,
'signers' => [[
'name' => 'أحمد محمد',
'email' => 'ahmed@example.com',
'type' => 'individual',
'method' => 'draw',
'require_identity' => true,
'fields' => ['job_title' => 'مهندس برمجيات', 'salary' => '25000'],
]],
'reminders' => ['enabled' => true, 'interval_hours' => 48, 'max' => 3],
'metadata' => ['order_id' => 'A-1024'],
], ['idempotency_key' => bin2hex(random_bytes(16))]);
echo $sr->id . ' ' . $sr->status; // sr_3n8Kd2Qa1V sent// autoPagingIterator يجلب الصفحات التالية تلقائيًا عبر المؤشّر
foreach ($wt->signatureRequests->all(['status' => 'completed', 'limit' => 100]) as $sr) {
echo $sr->id . ' ' . $sr->reference . "\n";
}require 'vendor/autoload.php';
$payload = file_get_contents('php://input');
$sig = $_SERVER['HTTP_WTHAIQ_SIGNATURE'] ?? '';
$secret = getenv('WTHAIQ_WEBHOOK_SECRET');
try {
$event = \Wthaiq\Webhook::constructEvent($payload, $sig, $secret);
} catch (\Wthaiq\Exception\SignatureVerificationException $e) {
http_response_code(400);
exit('invalid signature');
}
if ($event->type === 'signature_request.completed') {
$sr = $event->data->object; // كائن signature_request
// فعّل الحساب أو خزّن الوثيقة الموقّعة
}
http_response_code(200);Wthaiq-Signature: t=...,v1=... والسرّ whsec_...، وتقارن بمقارنة ثابتة الزمن مع رفض أي طلب يتجاوز فارقه الزمني 300 ثانية.نلتزم بحدود متوقّعة للتغيير حتى تُخطّط ترقياتك بثقة، ونفصل بين إصدار المكتبة وإصدار الـAPI.
تتبع كل مكتبة الترقيم الدلالي MAJOR.MINOR.PATCH. لا تُدخَل أي تغييرات كاسِرة إلا في إصدار رئيسي (MAJOR) جديد؛ أما الإضافات المتوافقة وإصلاحات الأخطاء فتصدر في MINOR وPATCH بأمان.
إصدار المكتبة مستقلّ عن إصدار الـAPI المثبَّت عبر Wthaiq-Version، فيمكنك ترقية المكتبة دون تغيير سلوك الـAPI.
تغييرات الـAPI مؤرَّخة عبر ترويسة الإصدار، وأي إصدار مطروح يبقى مدعومًا. عند إيقاف قدرة قديمة نُعلن عنها في سجل التغييرات، ونمنح مهلة انتقال لا تقل عن 12 شهرًا قبل الإزالة.
تصدر تنبيهات الإيقاف أيضًا عبر ترويسات الاستجابة وسجلات المكتبة، فتعرف مبكرًا ما يحتاج إلى تحديث. راجِع سجل التغييرات بانتظام.
| اللغة | الحد الأدنى لبيئة التشغيل | مصدر الحزمة | الإصدار |
|---|---|---|---|
| Node.js | Node.js 18+ | npm · @wthaiq/node | v1.x |
| Python | Python 3.8+ | PyPI · wthaiq | v1.x |
| PHP | PHP 8.1+ | Packagist · wthaiq/wthaiq-php | v1.x |
| Go | Go 1.21+ | pkg.go.dev · wthaiq/wthaiq-go | v1.x |
| Ruby | Ruby 3.0+ | RubyGems · wthaiq | v1.x |
| .NET | .NET 6.0+ | NuGet · Wthaiq | v1.x |
Wthaiq-Version: 2026-07-01 افتراضيًا، وتتصل بـhttps://wthaiq.com/api/v1، وتصادِق عبر Authorization: Bearer sk_.... لا يوجد وضع اختبار — كل مفتاح sk_ حيّ فور إنشائه؛ المفتاح العام pk_... للاستخدام الآمن في المتصفّح يبقى محدودًا بمسارات ونطاقات معيّنة.ننشر ست مكتبات رسمية: Node.js وPython وPHP كمكتبات الفئة الأولى (tier-1) بأمثلة كاملة ودعم أوسع، إضافة إلى Go وRuby و.NET. جميعها تتشارك واجهة الموارد وأسماء العمليات نفسها، فما تتعلّمه في لغة ينطبق مباشرة على الباقي.
نعم، جميع المكتبات مفتوحة المصدر ومنشورة على منظّمة github.com/wthaiq، ويمكنك تتبّع الشيفرة وفتح المشكلات والمساهمة. تُوزَّع الحزم عبر مصادرها القياسية: npm وPyPI وPackagist وpkg.go.dev وRubyGems وNuGet.
تُعيد المكتبة المحاولة تلقائيًا على أخطاء الشبكة والردود العابرة (429 و5xx) بتراجع أُسّي، وترفق مع كل طلب POST مفتاح Idempotency-Key فريدًا. بما أن المفتاح يُخزَّن على الخادم 24 ساعة، فإن أي إعادة محاولة لا تُنشئ موردًا مكرّرًا. يمكنك أيضًا تمرير مفتاحك الخاص لكل طلب.
تُرسل كل مكتبة ترويسة Wthaiq-Version: 2026-07-01 مثبَّتة افتراضيًا مع كل طلب، فتبقى استجابات الـAPI ثابتة الشكل رغم أي تحديثات لاحقة. يمكنك تجاوز الإصدار عند تهيئة العميل أو لكل طلب على حِدة عند رغبتك في اعتماد إصدار أحدث بعد اختباره.
الحد الأدنى: Node.js 18، وPython 3.8، وPHP 8.1، وGo 1.21، وRuby 3.0، و.NET 6.0. تتبع المكتبات ترقيم SemVer، فلا تغييرات كاسِرة إلا في إصدار رئيسي جديد. عند إيقاف أي قدرة نُعلن عنها في سجل التغييرات ونمنح مهلة انتقال لا تقل عن 12 شهرًا قبل الإزالة.
ابدأ بالمكتبة المناسبة للغتك، واتبع دليل البدء السريع لإنشاء أول طلب توقيع خلال دقائق — بأنواع مضمّنة وحجّية قانونية كاملة.