لا توجد نقاط نهاية مطابقة
لا شيء هنا يطابق
أرسل ترويسة X-App-Secret الخاصة بتطبيقك، وأرسل JSON عبر POST إلى /api/auth/* للتحقّق من المفاتيح وتشغيل الجلسات. أنشئ المفاتيح من /api/admin/* برمز Bearer. الاستجابات دائمًا { "success": true|false, … }.
مقدّمة
واجهة PWF Auth مبنية على نمط REST. كل الطلبات والاستجابات بصيغة JSON عبر HTTPS. هناك ثلاث عائلات من النقاط:
- واجهة العميل (
/api/auth/*،/api/update/*) — تُستدعى من تطبيقك المنشور باستخدام سرّ التطبيق. - واجهة الأدمن (
/api/admin/*) — إدارة المفاتيح والتطبيقات، بمصادقة رمز Bearer. - واجهة العميل/الموزّع (
/api/customer/*،/api/reseller/*) — بوّابات خدمة ذاتية.
كل المسارات أدناه نسبيّة إلى هذا العنوان الأساسي. كل نقطة تتطلّب HTTPS؛ وطلبات HTTP العادية يُعاد توجيهها.
تفضّل الآلات؟ السطح كامل موصوف في openapi.json (OpenAPI 3.1) — استورده في Postman أو Insomnia أو مولّد الأكواد لديك.
تغييرات الواجهة والمنصة تُعلَن في سجل التغييرات — والتغييرات الكاسرة تُعلَّم هناك أولاً دائماً.
المصادقة
نقاط العميل — سرّ التطبيق
أرسل سرّ تطبيقك في ترويسة X-App-Secret. تجده في لوحة التحكّم ← تطبيقك. يحدّد السرّ التطبيقَ الذي ينتمي إليه الطلب.
curl https://pwfauth.com/api/auth/check-key.php \
-H "X-App-Secret: 9f02532d9c60… # 64-char hex, from your dashboard" \
-H "Content-Type: application/json" \
-d '{"license_key":"XXXXX-XXXXX-XXXXX-XXXXX"}'
نقاط الأدمن — رمز Bearer
صادِق عبر /api/admin/login.php للحصول على JWT، ثم أرسله بصيغة Authorization: Bearer <token> في كل استدعاء أدمن.
TOKEN=$(curl -s https://pwfauth.com/api/admin/login.php \
-d '{"username":"admin","password":"…"}' | jq -r .token)
curl https://pwfauth.com/api/admin/keys.php \
-H "Authorization: Bearer $TOKEN"
التغليف المشفّر
نقاط النهاية بمستوى الـ SDK تتبادل تغليف AES-256-CBC + HMAC-SHA256 بدل JSON العادي. صيغة النقل: {"p": base64(IV || ciphertext), "t": unix_timestamp, "s": hmac_sha256_hex(p + t)} — مفتاحا التشفير والتوقيع يُشتقّان كلاهما من سرّ تطبيقك، فلا حاجة لأي تبادل مفاتيح إضافي.
{
"p": "aXYxNmJ5dGVzY2lwaGVydGV4dA…", // base64( IV || AES-256-CBC ciphertext )
"t": 1785671000, // unix timestamp (±300s accepted)
"s": "b7fd09…" // hmac_sha256_hex( p + t, mac_key )
}
النقاط المعلَّمة سرّ التطبيق + تغليف مشفّر تتطلبه في الطلب وتردّ مشفّرة. أما check-key.php فيكتشف تلقائياً: أرسل JSON عادياً تستلم JSON عادياً (وهذا ما يجعل أمثلة curl في هذه الصفحة تعمل)؛ أرسل تغليفاً يأتيك الرد مشفّراً.
التغليفات الأقدم من ±300 ثانية تُرفض، فحافظ على دقة ساعة الجهاز. ولا تحتاج بناء هذا يدوياً: العملاء المفتوحون (VB.NET وC# وPython) يتضمنون تنفيذ CryptoEnvelope جاهزاً.
كيف يُبنى المظروف
الاتجاهان يستخدمان الوصفة نفسها. يُشتق مفتاحان من سر تطبيقك، فيحصل كل تطبيق على مفتاحي تشفير وتوقيع مستقلّين:
enc_key = SHA256("enc:" + app_secret) # 32 bytes
mac_key = SHA256("mac:" + app_secret) # 32 bytes
# client → server (and server → client — same recipe)
iv = random_bytes(16)
ct = AES-256-CBC(enc_key, iv, json_body) # PKCS#7 padding
p = base64(iv || ct)
t = unix_time() # ±300 s accepted
s = hex(HMAC-SHA256(p + str(t), mac_key))
send { "p": p, "t": t, "s": s }
# receiving: verify s FIRST (constant-time), check |now - t| ≤ 300,
# then base64-decode p, split off the 16-byte IV, decrypt the rest.
أي نقاط النهاية تتطلبه
كل بطاقة نقطة نهاية تحمل شارة مصادقة ملوّنة؛ وهذا الجدول يجمع المعلومة نفسها بنظرة واحدة:
| نموذج المصادقة | نقاط النهاية |
|---|---|
| عام | app/changelog · app/pricing · admin/login |
| سرّ التطبيق · عادي أو مغلّف | auth/check-key |
| سرّ التطبيق | auth/trial · auth/request-hwid-reset · auth/account-register · auth/account-login · auth/change-password · update/validate · update/download |
| سرّ التطبيق + تغليف مشفّر | auth/login · auth/heartbeat · auth/logout · app/text · app/slides · app/info · app/social-click · update/check |
| Bearer | admin/* |
| سرّ إتمام الطلبات | app/fulfill |
الاستجابات والأخطاء
كل استجابة تحمل قيمة منطقية success. والأخطاء تضيف رسالة بشرية message ورمزًا ثابتًا قابلًا للقراءة آليًا error_code:
{
"success": false,
"message": "This license key has been banned.",
"error_code": "BANNED"
}
| error_code | المعنى |
|---|---|
MISSING_FIELDS | حقل مطلوب في الجسم غير موجود. |
INVALID_KEY | مفتاح الترخيص غير موجود لهذا التطبيق. |
INVALID_CREDENTIALS | اسم المستخدم/كلمة المرور مرفوضان (حسابات المستخدمين + دخول الأدمن). |
HWID_MISMATCH | المفتاح مرتبط بجهاز آخر. |
EXPIRED | انتهت صلاحية الترخيص. |
BANNED / PAUSED | تم حظر المفتاح أو إيقافه مؤقتًا من المالك. |
MAINTENANCE | التطبيق في وضع الصيانة. |
SESSION_EXPIRED / SESSION_MISMATCH | جلسة النبض غير صالحة. |
TOO_MANY_ATTEMPTS | قفل الحماية من تخمين كلمات المرور — يُقفل الحساب مؤقتاً؛ حقل retry_after في الرد يحدد المدة بالثواني. |
TRIAL_DISABLED / TRIAL_USED / TRIAL_LIMIT | رُفض إنشاء التجربة — معطّلة لهذا التطبيق، أو استُخدمت على هذا الجهاز، أو بلغت حدّ الـ IP. |
أكواد حالة HTTP
| error_code | المعنى |
|---|---|
200 | نجاح — جسم JSON يحمل النتيجة. |
400 | فشل تحقق — حقول ناقصة أو مشوهة (راجع error_code). |
401 | X-App-Secret أو Bearer token مفقود أو غير صالح. |
403 | موثَّق لكن غير مسموح (تطبيق آخر، توكن ملغى…). |
404 | المورد غير موجود. |
405 | طريقة HTTP خاطئة لهذه النقطة. |
429 | تجاوز حد الطلبات — انتظر مدة ترويسة Retry-After قبل إعادة المحاولة. |
500 | خطأ خادم — الرسالة عامة عمداً؛ أعد المحاولة لاحقاً. |
حدود المعدل والاستخدام العادل
يحمي محدِّد طلبات عام لكل عنوان IP جميع نقاط النهاية — الإغراق يعيد 429 مع ترويسة Retry-After (وللمدراء الموثّقين سقف أعلى). وفوق ذلك حرّاس موجَّهون:
- دخول الأدمن محمي من التخمين — الإخفاقات المتكررة تقفل الحساب مؤقتاً.
- التجارب محدودة لكل جهاز (HWID) ولكل IP؛ تجاوزها يرجع
TRIAL_LIMIT. - إعادة توليد السر محدودة المعدل لكل تطبيق لمنع حلقات التدوير العرضية.
- أبقِ الheartbeats على الفاصل الذي يرجعه ردّ الدخول (30 ثانية افتراضاً) — الأسرع لا يضيف شيئاً.
بداية سريعة
أدنى تكامل: تحقّق من المفتاح عند تشغيل تطبيقك، ثم أرسل نبضًا للإبقاء على الجلسة حيّة.
# Validate a key from the terminal (plain JSON works here)
curl -X POST https://pwfauth.com/api/auth/check-key.php \
-H "X-App-Secret: $APP_SECRET" \
-d '{"license_key":"XXXXX-XXXXX-XXXXX-XXXXX"}'
# → { "success": true, "valid": true, "key": { "status": "active", … } }
ملاحظة: تدفق الجلسة الكامل (دخول ← heartbeat ← خروج) يستخدم التغليف المشفّر، فلا يمكن تجربته بـ curl يدوياً. اربطه في دقائق عبر معالج البدء السريع داخل اللوحة (يولّد مقتطفات بـ9 لغات ببياناتك الحقيقية) أو العملاء المفتوحين.
التدفق نفسه عبر SDK رسمي
تسجيل الدخول ونبض القلب ومفتاح الإيقاف من جهة الخادم في أسطر قليلة — الـSDK يتكفّل بالمظروف المشفّر عنك:
// dotnet add package PWFAuth
using PWFAuth;
var client = new PwfClient(APP_SECRET);
client.SessionEnded += (s, e) => // ban / pause / expiry / revoke / offline
{
Console.WriteLine($"{e.ErrorCode}: {e.Message}");
Environment.Exit(0);
};
var login = await client.LoginAsync("XXXXX-XXXXX-XXXXX-XXXXX");
if (!login.Success) { Console.WriteLine(login.Message); return; }
client.StartHeartbeat(); // keeps the session alive AND enforces the kill switch
' dotnet add package PWFAuth
Dim client As New PwfClient(APP_SECRET)
AddHandler client.SessionEnded, Sub(s, e) ' ban / pause / expiry / revoke / offline
MessageBox.Show(e.Message)
Application.Exit()
End Sub
Dim login = Await client.LoginAsync("XXXXX-XXXXX-XXXXX-XXXXX")
If login.Success Then client.StartHeartbeat()
# pip install pwfauth
import sys
from pwfauth import PwfClient
client = PwfClient(APP_SECRET)
client.on_session_ended = lambda code, msg: sys.exit(msg) # kill switch
login = client.login("XXXXX-XXXXX-XXXXX-XXXXX")
if not login.success:
sys.exit(login.message)
client.start_heartbeat() # keeps the session alive AND enforces the kill switch
// npm install pwfauth
import { PwfClient } from 'pwfauth';
const client = new PwfClient(process.env.PWFAUTH_SECRET);
client.on('sessionEnded', ({ errorCode, message }) => { // kill switch
console.error(`${errorCode}: ${message}`);
process.exit(1);
});
const login = await client.login('XXXXX-XXXXX-XXXXX-XXXXX');
if (!login.success) { console.error(login.message); process.exit(1); }
client.startHeartbeat(); // keeps the session alive AND enforces the kill switch
التراخيص والجلسات
فعّل المفتاح عند أول استخدام، واربطه بـHWID الجهاز، وافتح جلسة. يعيد التحقّق ويبدأ جلسة جديدة في عمليات الدخول اللاحقة. ويفرض max_devices بإنهاء أقدم جلسة.
| حقل الجسم | إلزامي؟ | الوصف |
|---|---|---|
license_key | مطلوب | مفتاح الترخيص المراد تفعيله/التحقّق منه. |
hwid | مطلوب | بصمة عتاد ثابتة للجهاز. |
{
"success": true,
"session_id": "8f2c…",
"user": {
"license_key": "XXXXX-XXXXX-XXXXX-XXXXX",
"key_type": "days", "duration": 30,
"expires_at": "2026-09-01T12:00:00Z",
"days_remaining": 30, "status": "active"
},
"features": { "pro_tier": true },
"heartbeat_interval": 30
}
أبقِ الجلسة نشطة. استدعِها كل heartbeat_interval ثانية (يعيدها login). توقّف عن الاستدعاء فتُنهى الجلسة من الخادم.
| حقل الجسم | إلزامي؟ | الوصف |
|---|---|---|
session_id | مطلوب | الجلسة التي يعيدها login. |
license_key | اختياري | إن أُرسل، يجب أن تنتمي الجلسة لهذا المفتاح. |
{ "success": true, "message": "Heartbeat received" }
// the moment the key is banned / paused / expired / reset, the SAME call answers:
{ "success": false, "error_code": "BANNED",
"message": "This license key has been banned." } // session is dropped — log the user out
أغلق الجلسة فورًا (مثلًا عند إغلاق التطبيق). الجسم: session_id مطلوب، license_key اختياري.
بحث خفيف عن الحالة — دون إنشاء جلسة أو ربط HWID. مفيد لفحص «هل ما زال هذا المفتاح صالحًا؟».
| حقل الجسم | إلزامي؟ | الوصف |
|---|---|---|
license_key | مطلوب | المفتاح المراد فحصه. |
curl -X POST https://pwfauth.com/api/auth/check-key.php \
-H "X-App-Secret: $APP_SECRET" \
-d '{"license_key":"XXXXX-XXXXX-XXXXX-XXXXX"}'
var http = new HttpClient();
http.DefaultRequestHeaders.Add("X-App-Secret", APP_SECRET);
var res = await http.PostAsync("https://pwfauth.com/api/auth/check-key.php",
new StringContent("{\"license_key\":\"XXXXX-XXXXX-XXXXX-XXXXX\"}"));
import urllib.request, json
req = urllib.request.Request("https://pwfauth.com/api/auth/check-key.php",
data=json.dumps({"license_key": "XXXXX-XXXXX-XXXXX-XXXXX"}).encode(),
headers={"X-App-Secret": APP_SECRET})
print(json.load(urllib.request.urlopen(req)))
const res = await fetch('https://pwfauth.com/api/auth/check-key.php', {
method: 'POST',
headers: { 'X-App-Secret': process.env.APP_SECRET },
body: JSON.stringify({ license_key: 'XXXXX-XXXXX-XXXXX-XXXXX' })
});
console.log(await res.json());
$ch = curl_init('https://pwfauth.com/api/auth/check-key.php');
curl_setopt_array($ch, [CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['X-App-Secret: ' . $APP_SECRET],
CURLOPT_POSTFIELDS => '{"license_key":"XXXXX-XXXXX-XXXXX-XXXXX"}']);
$res = json_decode(curl_exec($ch), true);
{
"success": true, "valid": true,
"key": {
"status": "active", "key_type": "days", "duration": 30,
"activated_at": "2026-08-02T12:00:00Z",
"expires_at": "2026-09-01T12:00:00Z",
"days_remaining": 30, "max_devices": 1
}
}
تحقق خفيف من الترخيص بدون ربط HWID أو جلسة — مثالي كفحص مسبق قبل الدخول الكامل. JSON عادي دخولاً وخروجاً.
| حقل الجسم | إلزامي؟ | الوصف |
|---|---|---|
license_key | مطلوب | المفتاح المراد فحصه. |
أرسل طلب إعادة تعيين HWID من نافذة تطبيقك عندما يغيّر المستخدم جهازه. يوافق عليه مالك التطبيق من لوحة التحكّم.
| حقل الجسم | إلزامي؟ | الوصف |
|---|---|---|
license_key or username | مطلوب | يحدّد ربطَ مَن سيُعاد تعيينه. |
reason | اختياري | ملاحظة تظهر للمالك. |
التجارب المجانية
أصدر مفتاح تجربة محدود الوقت مرتبطًا بالجهاز الطالب. تجربة واحدة لكل HWID لكل تطبيق. ومدة التجربة يضبطها مالك التطبيق.
| حقل الجسم | إلزامي؟ | الوصف |
|---|---|---|
hwid | مطلوب | بصمة الجهاز الطالب للتجربة. |
{
"success": true, "message": "Trial activated! You have 3 days.",
"trial_key": "TRIAL-1A2B3-C4D5E-F6A7B",
"session_id": "8f2c…",
"expires_at": "2026-08-23T12:00:00Z", "days_remaining": 3,
"user": { "key_type": "days", "status": "active", … },
"app": { "name": "…", "version": "…" }
}
حسابات المستخدمين
تفضّل الدخول باسم مستخدم/كلمة مرور بدل المفاتيح الخام؟ يوفّر PWF Auth نموذج حسابات كامل مع تجزئة bcrypt وربط HWID.
أنشئ حساب مستخدم نهائي. الجسم: username، password مطلوب، email اختياري.
| حقل الجسم | إلزامي؟ | الوصف |
|---|---|---|
username | مطلوب | اسم المستخدم المطلوب (فريد لكل تطبيق). |
password | مطلوب | كلمة المرور (تُخزَّن مجزّأة). |
email | اختياري | بريد التواصل للحساب. |
صادِق واربط جهازًا. الجسم: username، password، hwid مطلوب. يعيد نفس شكل الجلسة كـlogin.
| حقل الجسم | إلزامي؟ | الوصف |
|---|---|---|
username | مطلوب | اسم مستخدم الحساب. |
password | مطلوب | كلمة مرور الحساب. |
hwid | مطلوب | بصمة الجهاز لربط الجلسة بها. |
غيّر كلمة مرور مستخدم. الجسم: username، current_password، new_password مطلوب.
| حقل الجسم | إلزامي؟ | الوصف |
|---|---|---|
username | مطلوب | اسم مستخدم الحساب. |
current_password | مطلوب | كلمة المرور الحالية (تُتحقق قبل التغيير). |
new_password | مطلوب | كلمة المرور الجديدة. |
محتوى التطبيق والتحكم عن بُعد
هذه النقاط تتيح لتطبيقك المنشور سحب محتوى تحرّره حيّاً من اللوحة — نصوص وشرائح وأسعار وسجلّ تغييرات — بدون إصدار تحديث.
جلب النص/النصوص الريموت. مع ?name=… يرجع مدخلاً واحداً؛ بدونه يرجع كل نصوص التطبيق. تجاوزات المفتاح تغلب افتراضيات التطبيق. مفتاح الترخيص يمرّ في Authorization: Bearer
| حقل الجسم | إلزامي؟ | الوصف |
|---|---|---|
?name | اختياري | مفتاح النص المطلوب (احذفه للكل). |
يرجع شرائح الإعلانات الفعّالة للتطبيق. أرسل تغليف {"action":"get_slides"}؛ الرد مشفّر.
بيانات التطبيق + روابط التواصل (الاسم، الهوية، الروابط). الرد مغلّف.
زيادة عدّاد نقرات رابط تواصل (لإحصاءات التفاعل في اللوحة).
| حقل الجسم | إلزامي؟ | الوصف |
|---|---|---|
link_id | مطلوب | المعرّف الرقمي للرابط. |
خلاصة سجلّ تغييرات عامة بلا مصادقة لتطبيق واحد — اعرض ودجت "ما الجديد" في أي مكان. المدخلات المنشورة فقط.
| حقل الجسم | إلزامي؟ | الوصف |
|---|---|---|
?app_id | مطلوب | التطبيق المطلوب سجلّه. |
?limit | اختياري | من 1 إلى 50، افتراضياً 20. |
?since | اختياري | تاريخ ISO — المدخلات المنشورة منه فصاعداً. |
?category | اختياري | تصفية: new / improved / fixed / removed / security / deprecated. |
واجهة أسعار عامة: مستويات الاشتراك والخطط القديمة؛ POST ينشئ طلب شراء؛ ?action=check يقرأ اشتراك مستخدم فعّال.
| حقل الجسم | إلزامي؟ | الوصف |
|---|---|---|
?app_id | مطلوب | التطبيق المطلوبة أسعاره. |
?type | اختياري | levels أو plans (احذفه للاثنين). |
إتمام طلبات خادم-لخادم لبوابات الدفع الآلية — إشعار دفع موثَّق يكمل الطلب ويولّد المفتاح ويسلّمه بلا موافقة يدوية. المصادقة بسرّ الإتمام المشترك من إعدادات لوحتك، وليس بجلسة مستخدم أبداً.
| حقل الجسم | إلزامي؟ | الوصف |
|---|---|---|
order_id | مطلوب | الطلب المراد إتمامه (ORD-…). |
secret | مطلوب | سرّ order_fulfill_secret الخاص بك. |
payment_ref | اختياري | مرجع دفع اختياري من البوابة. |
تحديثات OTA
اسأل ما إذا كان هناك إصدار أحدث متاحًا للمستدعي — مع مراعاة القناة، ومرشّحات نظام التشغيل/المعمارية، وحدّ الإصدار الأدنى، والطرح المرحلي (يُوضع المستدعي نفسه في نفس الشريحة بثبات).
| حقل الجسم | إلزامي؟ | الوصف |
|---|---|---|
v | مطلوب | الإصدار الحالي للمستدعي (semver). |
channel | اختياري | stable (افتراضي)، beta، أو alpha. |
os / arch | اختياري | windows·macos·linux / x64·x86·arm64. |
hwid / license_key | اختياري | يُستخدم لتوزيع الطرح الثابت. |
{
"success": true, "update_available": true,
"update": {
"version": "1.4.0", "channel": "stable",
"is_mandatory": false, "file_size": 5242880,
"sha256": "…", "changelog": "…",
"download_url": "api/update/download.php?v=1.4.0"
}
}
نزّل الملف الثنائي لإصدار معيّن. استخدم download_url الذي يعيده check.php، وتحقّق من sha256 بعد التنزيل.
Webhooks
حوِّل الأحداث إلى استدعاءات HTTP نحو خادمك: تفعيلات المفاتيح، الحظر، الانتهاء، الطلبات، التحديثات الجديدة وغيرها. جهِّز الوجهات لكل تطبيق (أو لكل التطبيقات) من اللوحة تحت Application → Webhooks، واختر الأحداث التي تهمك، وسيرسل PWF Auth جسم JSON موقَّعاً إلى رابطك بطلب POST. التسليم عبر طابور — توقَّعه خلال دقيقة أو دقيقتين من الحدث، لا في اللحظة نفسها.
حمولة التسليم
{
"event": "key.activated",
"timestamp": "2026-08-20T14:07:02Z",
"data": {
"app_id": "01af6643-…",
"license_key": "XXXXX-XXXXX-XXXXX-XXXXX",
"hwid": "A1B2C3…"
}
}
ترويسات التسليم
| الترويسة | الوصف |
|---|---|
X-Webhook-Id | معرّف تسليم فريد (whd_…). يبقى نفسه عبر إعادات المحاولة للحدث الواحد — استخدمه لمنع التكرار. |
X-Webhook-Timestamp | طابع Unix الزمني لمحاولة التسليم. |
X-Webhook-Attempt | عدّاد المحاولات يبدأ من 1. |
X-Webhook-Signature | التوقيع القديم: hex(HMAC-SHA256(body, secret)). |
X-Webhook-Signature-V2 | التوقيع المفضَّل: t=<ts>,v1=hex(HMAC-SHA256(ts + "." + body, secret)) — وجود الطابع الزمني داخل الـMAC يجعل إعادة الإرسال قابلة للكشف. |
التحقق من التوقيع
تحقَّق دائماً قبل الوثوق بأي تسليم: احسب MAC النسخة الثانية على timestamp + "." + raw body بسر نقطتك، وقارن بزمن ثابت، وارفض الطوابع القديمة (±5 دقائق تكفي). أجب بـ2xx بسرعة — الأعمال الثقيلة مكانها طابورك الخاص.
// X-Webhook-Signature-V2: t=<ts>,v1=<hex>
[$t, $v1] = explode(',', $_SERVER['HTTP_X_WEBHOOK_SIGNATURE_V2'] ?? ',');
$t = substr($t, 2); $v1 = substr($v1, 3);
$raw = file_get_contents('php://input');
$ok = hash_equals(hash_hmac('sha256', $t . '.' . $raw, $secret), $v1)
&& abs(time() - (int)$t) < 300;
if (!$ok) { http_response_code(400); exit; }
http_response_code(200); // answer fast — queue heavy work
// X-Webhook-Signature-V2: t=<ts>,v1=<hex>
const [t, v1] = req.headers['x-webhook-signature-v2']
.split(',').map(kv => kv.split('=')[1]);
const mac = crypto.createHmac('sha256', secret)
.update(`${t}.${rawBody}`).digest('hex');
const ok = crypto.timingSafeEqual(Buffer.from(mac), Buffer.from(v1))
&& Math.abs(Date.now() / 1000 - Number(t)) < 300;
res.sendStatus(ok ? 200 : 400); // answer fast — queue heavy work
# X-Webhook-Signature-V2: t=<ts>,v1=<hex>
import hmac, time
t, v1 = (kv.split("=", 1)[1]
for kv in request.headers["X-Webhook-Signature-V2"].split(","))
mac = hmac.new(secret, f"{t}.{raw_body}".encode(), "sha256").hexdigest()
ok = hmac.compare_digest(mac, v1) and abs(time.time() - int(t)) < 300
return ("", 200) if ok else ("", 400) # answer fast — queue heavy work
إعادة المحاولة وسياسة الفشل
- يُعَد التسليم ناجحاً عند أي رد
2xx/3xxخلال 5 ثوانٍ. - الفشل يُعاد حتى 5 محاولات بفجوات متزايدة: 1د ← 5د ← 30د ← 2س ← 6س.
X-Webhook-Idيُسَكّ مرة واحدة لكل حدث ويُعاد استخدامه في كل محاولة — منع التكرار يصبح فحصseen?واحداً.- الوجهة التي تفشل 20 مرة متتالية تُوقَف تلقائياً؛ أعد تفعيلها من اللوحة (وزر حدث
testموجود هناك).
الأحداث
اشترك بأحداث محددة أو اترك المرشِّح فارغاً لتستقبلها كلها. حقل event في الجسم يخبرك أيُّها وقع:
| الحدث | يقع عند |
|---|---|
key.created | توليد مفاتيح (من اللوحة أو واجهة الأدمن). |
key.activated | أول تسجيل دخول ناجح يربط المفتاح بجهاز. |
key.banned / key.unbanned | حظر مفتاح / رفع الحظر عنه. |
key.deleted | حذف مفتاح. |
key.rotated | تدوير نص المفتاح (النص القديم يتوقف عن العمل). |
key.suspected_leak | كشف التسريب يعلّم مفتاحاً كمشتبه بمشاركته أو تسريبه. |
key_expiring | اقتراب مفتاح من الانتهاء (مسح مجدول). |
key_expired | انتهاء مفتاح (مسح مجدول). |
trial.created | إصدار مفتاح تجريبي لجهاز جديد. |
hwid_reset.requested | طلب عميل إعادة تعيين الجهاز (HWID). |
new_order | إنشاء طلب شراء. |
order.approved | الموافقة على طلب وتنفيذه. |
subscription.* | دورة حياة الاشتراك: إنشاء / تجديد / إلغاء / إنشاء طلب تجديد. |
update.published | نشر إصدار جديد للتطبيق. |
changelog.published | نشر مُدخلة في سجل التغييرات. |
app.revoked | إبطال / تعطيل تطبيق. |
suspicious_activity | انطلاق كاشف النشاط المشبوه. |
test | تسليم تجريبي يدوي من اللوحة. |
واجهة الأدمن
نقاط من جهة الخادم لإدارة التطبيقات والمفاتيح. كلها تتطلّب رمز Authorization: Bearer من نقطة الدخول أدناه.
لا تريد تخزين كلمة مرورك داخل سكربت؟ أنشئ توكن وصول شخصياً من اللوحة ← الملف الشخصي ← API Tokens واستخدمه كقيمة Bearer (pwf_…). لا تنتهي صلاحيته حتى تلغيه بنفسك، ويعمل مع كل نقاط /api/admin/*، وهو ممنوع تصميمياً من إدارة بيانات الاعتماد (كلمة المرور، البريد، 2FA، إنشاء توكنات جديدة).
بدّل بيانات الاعتماد برمز JWT. إذا كان التحقّق الثنائي مفعّلًا، يعيد requires_2fa وstep1_token لإتمامه عبر /api/admin/totp.php.
| حقل الجسم | إلزامي؟ | الوصف |
|---|---|---|
username | مطلوب | اسم مستخدم الأدمن. |
password | مطلوب | كلمة مرور الأدمن. |
أنشئ مفاتيح ترخيص بالجملة. تدعم النقطة نفسها أيضًا GET (سرد)، PUT (تعديل)، DELETE، واستعلامات إجراءات مثل ?action=ban|pause|extend|reset-hwid و?action=export.
curl -X POST https://pwfauth.com/api/admin/keys.php \
-H "Authorization: Bearer $TOKEN" \
-d '{"app_id":"01af6643-cf3a-4280-b9ce-cb5fa8ae987c",
"count":100,"key_type":"days","duration_value":30}'
تغطّي واجهة الأدمن أيضًا apps، sessions، updates، feature-flags، webhooks، analytics، audit، resellers، والمزيد — كلها تحت /api/admin/ بنفس مصادقة Bearer. سجّل الدخول إلى لوحة التحكّم لاستكشافها.
حِزَم SDK
تعمل واجهة REST من أي شيء يستطيع إرسال طلب HTTP. الحِزَم الرسمية منشورة على السجلّات العامة — PWFAuth على NuGet (C# / VB.NET)، وpwfauth على npm (JavaScript / Node.js) وعلى PyPI (Python) — إضافة إلى امتداد VS Code وأمثلة PHP من الدرجة الأولى. كل SDK يتكفّل عنك بالمظروف المشفّر ونبض القلب ومفتاح الإيقاف.
- عملاء أمثلة مفتوحو المصدر (VB.NET · C# · Python) — تدفقات دخول/heartbeat/تغليف كاملة جاهزة للنسخ
- البدء السريع داخل اللوحة — 5 خطوات موجَّهة تولّد مقتطفات تعمل بـ9 لغات ببياناتك الحقيقية
- مواصفة OpenAPI 3.1 (
openapi.json) — استيراد بنقرة واحدة في Postman / Insomnia، أو غذِّ بها مولّد الأكواد
جاهز للتكامل؟
أنشئ حسابًا مجانيًا، وسجّل تطبيقًا، وانسخ X-App-Secret من لوحة التحكّم.