📖

دليل ربط PRMGTK API

دليل شامل لربط منصة PRMGTK مع تطبيقاتك — Laravel، Node.js، Python أو أي لغة تدعم HTTP. كل مطوّر لديه instance_id وaccess_token خاص به للمصادقة.

١نظرة عامة

PRMGTK يوفّر REST API بسيط لإرسال رسائل واتساب نيابةً عن أي حساب مرتبط. كل عميل له instance_id ثابت وaccess_token فريد.

BASE URL

https://yourdomain.com

خطوات التهيئة

  1. 1أنشئ حسابك على المنصة أو سجّل من صفحة التسجيل
  2. 2اربط رقم واتساب بمسح QR من لوحة التحكم
  3. 3انسخ instance_id و access_token من صفحة حسابك
  4. 4ضع البيانات في .env الخاص بتطبيقك
  5. 5ابدأ الإرسال فوراً باستخدام الأمثلة أدناه

٢المصادقة

كل طلب API يحتاج معاملين يُرسلان في query string أو body:

المعاملمثالمكان الإرسال
instance_id0001query أو body
access_tokenprmgtk0001query أو body
⚠️أمان: لا تكشف access_token في كود الـ frontend أبداً. اجعل جميع الطلبات من الـ backend.

٣الـ Endpoints

GET/api/wa/statusحالة الجلسة والاشتراك
CURL
curl "https://yourdomain.com/api/wa/status?instance_id=0001&access_token=prmgtk0001"

الرد عند النجاح

JSON
{
  "ok": true,
  "status": "connected",
  "phone": "966501234567",
  "subscription": {
    "start": "2026-01-01T00:00:00.000Z",
    "end":   "2026-02-01T00:00:00.000Z",
    "days_remaining": 25
  }
}
GET/api/wa/qrcodeجلب كود QR لربط واتساب

يرجع كود QR بصيغة base64 PNG. يفشل لو كانت الجلسة متصلة بالفعل.

CURL
curl "https://yourdomain.com/api/wa/qrcode?instance_id=0001&access_token=prmgtk0001"
200QR جاهز
202lم يُولّد بعد — أعد بعد 3 ثوانٍ
409متصل بالفعل
JSON
{ "ok": true, "qr_base64": "data:image/png;base64,iVBORw0KGgo..." }
POST/api/wa/sendإرسال رسالة نصية

الرقم بصيغة دولية بدون + أو 00 (مثل: 966501234567)

المعاملمثالوصف
instance_id0001مُعرّف الحساب
access_tokenprmgtk0001رمز الوصول
number966501234567رقم المستلم
messageمرحباًنص الرسالة
CURL
curl -X POST "https://yourdomain.com/api/wa/send" \
  -d "instance_id=0001" \
  -d "access_token=prmgtk0001" \
  -d "number=966501234567" \
  -d "message=مرحباً من تطبيقي 👋"

الرد عند النجاح

JSON
{
  "ok": true,
  "message_id": "3EB0F5F0A8F5B26402B11D",
  "timestamp": 1700000000
}

٤كلاس Service جاهز — Laravel

أأضف في .env

.env
WA_GATEWAY_URL=https://yourdomain.com
WA_GATEWAY_INSTANCE_ID=0001
WA_GATEWAY_ACCESS_TOKEN=prmgtk0001

بأضف في config/services.php

PHP
'wa_gateway' => [
    'base_url'     => env('WA_GATEWAY_URL', 'https://yourdomain.com'),
    'instance_id'  => env('WA_GATEWAY_INSTANCE_ID'),
    'access_token' => env('WA_GATEWAY_ACCESS_TOKEN'),
],

جأنشئ app/Services/WaGateway.php

PHP
<?php

namespace App\Services;

use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;

class WaGateway
{
    protected string $baseUrl;
    protected string $instanceId;
    protected string $accessToken;

    public function __construct(?string $instanceId = null, ?string $accessToken = null)
    {
        $this->baseUrl     = rtrim(config('services.wa_gateway.base_url'), '/');
        $this->instanceId  = $instanceId  ?? config('services.wa_gateway.instance_id');
        $this->accessToken = $accessToken ?? config('services.wa_gateway.access_token');
    }

    /** حالة الجلسة */
    public function status(): array
    {
        return $this->get('status');
    }

    /** جلب QR لربط جلسة جديدة */
    public function qrcode(): array
    {
        return $this->get('qrcode');
    }

    /** إرسال رسالة نصية */
    public function send(string $number, string $message): array
    {
        return $this->post('send', [
            'number'  => $this->cleanNumber($number),
            'message' => $message,
        ]);
    }

    /** تنظيف الرقم: إزالة + و 00 والمسافات */
    protected function cleanNumber(string $n): string
    {
        $d = preg_replace('/\D+/', '', $n);
        if (str_starts_with($d, '00')) $d = substr($d, 2);
        return $d;
    }

    protected function get(string $endpoint): array
    {
        try {
            $r = Http::timeout(20)->acceptJson()
                ->get("{$this->baseUrl}/api/wa/{$endpoint}", $this->credentials());
            return $r->json() ?? ['ok' => false, 'error' => 'Empty response'];
        } catch (\Throwable $e) {
            Log::error('WaGateway GET failed', ['endpoint' => $endpoint, 'msg' => $e->getMessage()]);
            return ['ok' => false, 'code' => 'network_error', 'error' => $e->getMessage()];
        }
    }

    protected function post(string $endpoint, array $data): array
    {
        try {
            $r = Http::timeout(30)->acceptJson()->asForm()
                ->post("{$this->baseUrl}/api/wa/{$endpoint}", array_merge($this->credentials(), $data));
            return $r->json() ?? ['ok' => false, 'error' => 'Empty response'];
        } catch (\Throwable $e) {
            Log::error('WaGateway POST failed', ['endpoint' => $endpoint, 'msg' => $e->getMessage()]);
            return ['ok' => false, 'code' => 'network_error', 'error' => $e->getMessage()];
        }
    }

    protected function credentials(): array
    {
        return [
            'instance_id'  => $this->instanceId,
            'access_token' => $this->accessToken,
        ];
    }
}

٥أمثلة استخدام

إرسال رسالة بسيطة

PHP
use App\Services\WaGateway;

$wa  = new WaGateway();
$res = $wa->send('966501234567', 'مرحباً من Laravel 👋');

if ($res['ok']) {
    return "تم — message_id: {$res['message_id']}";
}
return "فشل: {$res['error']}";

التحقق من حالة الاتصال قبل الإرسال

PHP
$wa     = new WaGateway();
$status = $wa->status();

if (!$status['ok'] || $status['status'] !== 'connected') {
    return back()->with('error', 'الجلسة غير متصلة، اربط واتساب أولاً');
}

$wa->send($patient->phone, "موعدك في {$appointment->date}");

عميل مختلف لكل فرع / عيادة

PHP
// كل فرع لديه instance_id و access_token خاص به محفوظين في DB
$wa = new WaGateway($branch->wa_instance_id, $branch->wa_access_token);
$wa->send($customer->phone, $message);

إرسال جماعي (Broadcast)

PHP
foreach ($patients as $p) {
    $res = $wa->send($p->phone, "تذكير: موعدك غداً الساعة {$p->appt_time}");

    if (!$res['ok']) {
        Log::warning("فشل إرسال لـ {$p->phone}: {$res['error']}");
    }

    usleep(700_000); // 0.7 ثانية بين كل رسالة — لتفادي الحظر
}
⚠️ضع تأخيراً لا يقل عن 500ms بين كل رسالتين عند الإرسال الجماعي. الإرسال السريع جداً قد يؤدي لحظر الرقم.

Node.js / JavaScript

JavaScript
async function sendWhatsApp(number, message) {
  const res = await fetch('https://yourdomain.com/api/wa/send', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      instance_id:  process.env.WA_INSTANCE_ID,
      access_token: process.env.WA_ACCESS_TOKEN,
      number,
      message,
    }),
  });
  return res.json();
}

// الاستخدام
const result = await sendWhatsApp('966501234567', 'مرحباً 👋');
if (result.ok) console.log('تم:', result.message_id);

٦صفحة الربط الجاهزة (HTML)

قالب HTML كامل (HTML + CSS + JS في ملف واحد) يعرض QR ويراقب الاتصال تلقائياً. ضعه في موقعك واستبدل INSTANCE_ID_HERE وACCESS_TOKEN_HERE.

ℹ️القالب يستدعي /api/wa/qrcode كل 3 ثوانٍ تلقائياً ويعرض شاشة "تم الربط" عند الاتصال.
HTML
<!DOCTYPE html>
<html lang="ar" dir="rtl">
<head>
<meta charset="UTF-8">
<title>اربط واتسابك</title>
<link href="https://fonts.googleapis.com/css2?family=Cairo:wght@400;600;700;800&display=swap" rel="stylesheet">
<style>
  *{box-sizing:border-box;margin:0;padding:0}
  body{font-family:'Cairo',sans-serif;background:linear-gradient(135deg,#f0fdf4,#ecfdf5);
       min-height:100vh;display:flex;align-items:center;justify-content:center;padding:20px;color:#1f2937}
  .box{background:#fff;border-radius:20px;box-shadow:0 20px 50px rgba(0,0,0,.1);
       padding:36px;max-width:440px;width:100%;text-align:center}
  h1{font-size:20px;font-weight:800;margin-bottom:6px}
  .sub{color:#6b7280;font-size:13px;margin-bottom:24px}
  .stage{min-height:300px;display:flex;flex-direction:column;align-items:center;justify-content:center}
  .spinner{width:40px;height:40px;border:3px solid #e5e7eb;border-top-color:#16a34a;
           border-radius:50%;animation:spin 1s linear infinite}
  @keyframes spin{to{transform:rotate(360deg)}}
  .qr-box{padding:12px;background:#fff;border:1px solid #e5e7eb;border-radius:12px;
          box-shadow:0 4px 16px rgba(0,0,0,.06)}
  .qr-box img{width:220px;height:220px;display:block}
  .steps{text-align:right;margin:14px 0;padding:14px;background:#f5f3ff;border-radius:10px;
         font-size:13px;line-height:2;color:#374151;list-style:none;counter-reset:s}
  .steps li::before{content:counter(s)'. ';counter-increment:s;color:#6366f1;font-weight:700}
  .badge{display:inline-flex;align-items:center;gap:6px;padding:4px 14px;border-radius:999px;
         font-size:12px;font-weight:700;margin-bottom:10px}
  .badge.wait{background:#fef3c7;color:#d97706}
  .success{color:#16a34a}
  .success svg{width:56px;height:56px;margin-bottom:10px}
  .phone{font-size:22px;font-weight:800;direction:ltr;margin-top:6px}
  .err{color:#dc2626;padding:12px;background:#fef2f2;border-radius:10px;font-size:13px}
</style>
</head>
<body>
<div class="box">
  <div style="font-size:36px;margin-bottom:10px">📱</div>
  <h1>اربط حساب واتساب</h1>
  <p class="sub">امسح كود QR من هاتفك لتفعيل الإرسال الآلي</p>
  <div id="stage" class="stage">
    <div class="spinner"></div>
    <p style="margin-top:12px;color:#6b7280;font-size:13px">جاري التحميل...</p>
  </div>
</div>

<script>
(function(){
  var API   = "https://yourdomain.com";
  var IID   = "INSTANCE_ID_HERE";
  var TOKEN = "ACCESS_TOKEN_HERE";
  var el    = document.getElementById('stage');
  var lastQr = null;

  function showQR(qr){
    if(qr===lastQr) return; lastQr=qr;
    el.innerHTML=
      '<div class="badge wait">⏳ في انتظار المسح</div>'+
      '<ol class="steps">'+
        '<li>افتح <strong>واتساب</strong> على هاتفك</li>'+
        '<li>اذهب لـ الإعدادات ← <strong>الأجهزة المرتبطة</strong></li>'+
        '<li>اضغط <strong>ربط جهاز</strong> ووجّه الكاميرا للكود</li>'+
      '</ol>'+
      '<div class="qr-box"><img src="'+qr+'" alt="QR"></div>';
  }
  function showOK(phone){
    el.innerHTML=
      '<div class="success">'+
        '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">'+
          '<path d="M22 11.08V12a10 10 0 11-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/>'+
        '</svg>'+
        '<h2 style="font-size:17px;margin-bottom:4px">تم الربط بنجاح!</h2>'+
        (phone?'<div class="phone">+'+phone+'</div>':'')+
        '<p style="margin-top:8px;color:#6b7280;font-size:13px">حسابك جاهز لاستقبال طلبات الإرسال.</p>'+
      '</div>';
  }
  function showErr(msg){el.innerHTML='<div class="err">⚠ '+msg+'</div>';}

  function poll(){
    fetch(API+'/api/wa/qrcode?instance_id='+IID+'&access_token='+TOKEN,{cache:'no-store'})
      .then(function(r){return r.json().then(function(j){return{s:r.status,b:j};});})
      .then(function(res){
        if(res.b.ok && res.b.qr_base64){ showQR(res.b.qr_base64); setTimeout(poll,3000); }
        else if(res.s===409){
          fetch(API+'/api/wa/status?instance_id='+IID+'&access_token='+TOKEN)
            .then(function(r){return r.json();}).then(function(s){showOK(s.phone);});
        }
        else if(res.s===202){ setTimeout(poll,3000); }
        else if(res.s===401||res.s===403){ showErr(res.b.error||'بيانات اعتماد غير صحيحة'); }
        else{ showErr(res.b.error||'خطأ غير متوقع'); setTimeout(poll,5000); }
      })
      .catch(function(){ showErr('فشل الاتصال بالخادم'); setTimeout(poll,5000); });
  }
  poll();
})();
</script>
</body>
</html>

٧أكواد الأخطاء

HTTPcodeالمعنى
200نجاح
202qr_not_readyكود QR لم يُولّد بعد — أعد المحاولة بعد 3 ثوانٍ
400invalid_inputالمعاملات ناقصة أو غير صالحة
400invalid_numberالرقم قصير أو طويل جداً
400number_not_registeredالرقم غير مسجّل في WhatsApp
400session_not_connectedالجلسة ليست متصلة — اربط QR أولاً
400timeoutالإرسال استغرق وقتاً طويلاً
401missing_credentialsinstance_id أو access_token مفقود
401invalid_credentialsبيانات الاعتماد غير صحيحة
403subscription_expiredانتهى اشتراك العميل
409already_connectedالجلسة متصلة بالفعل (عند طلب QR)

٨أخطاء شائعة وحلولها

الرسالة لا تُرسل ولا يظهر خطأ
السبب: الرقم بصيغة خاطئة (يبدأ بـ + أو 00 أو فيه مسافات). الحل: مرّر رقماً بصيغة دولية كاملة مثل 966501234567. كلاس الـ Service ينظّف الرقم تلقائياً.
session_not_connected
السبب: العميل لم يمسح QR أو فُصلت الجلسة. الحل: ادخل لوحة التحكم → افتح صفحة العميل → امسح QR من جديد.
number_not_registered
السبب: الرقم غير مسجّل في WhatsApp. الحل: تأكد من صحة الرقم وكود الدولة. الـ API يفحص أولاً قبل الإرسال.
subscription_expired
السبب: انتهت مدة اشتراك هذا العميل. الحل: جدّد الاشتراك من لوحة التحكم.
أول رسالة لرقم جديد بطيئة (5–15 ثانية)
طبيعي. النظام يبني مفاتيح تشفير مع المستلم لأول مرة. الرسائل التالية لنفس الرقم فورية. زد timeout في Http إلى 30 ثانية على الأقل.
الإرسال الجماعي يتوقف أو يُحظر
ضع تأخيراً لا يقل عن 500ms بين كل رسالتين. تجنّب إرسال نفس النص حرفياً لجميع المستلمين — نوّع قليلاً باسم الشخص أو التاريخ.

جاهز للبدء؟

سجّل الآن واحصل على 7 أيام تجربة مجانية

🚀 ابدأ مجاناً