📖

دليل ربط WASHIP API

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

١نظرة عامة

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

BASE URL

https://waship.prmgtk.com

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

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

٢المصادقة

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

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

٣الـ Endpoints

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

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

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://waship.prmgtk.com/api/wa/qrcode?instance_id=ws3f9a2c1d&access_token=a3f9c2d1e4b5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1"
200QR جاهز
202lم يُولّد بعد — أعد بعد 3 ثوانٍ
409متصل بالفعل
JSON
{ "ok": true, "qr": "data:image/png;base64,iVBORw0KGgo..." }
POST/api/wa/sendإرسال رسالة نصية

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

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

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

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

٤تعدد الأجهزة

كل حساب يمكنه ربط أكثر من جهاز واتساب بحسب الباقة المشترك فيها (حقل devices_limit). كل جهاز يعمل باستقلالية تامة وله بيانات اعتماد مستقلة.

ℹ️عدد الأجهزة المسموح بها يحدده المشرف من إعدادات الباقة. القيمة 0 تعني غير محدود.

مثال: استخدام جهاز محدد من الـ API الخارجي

لإرسال رسالة عبر جهاز معين، استخدم instance_id وaccess_token الخاصين بذلك الجهاز:

JavaScript
// جهاز رقم 1 (مثلاً للسعودية)
await sendWhatsApp({
  instanceId: 'ws3f9a2c1d',
  accessToken: 'a3f9c2d1e4b5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1',
  number: '966501234567',
  message: 'رسالة من الجهاز الأول'
});

// جهاز رقم 2 (مثلاً للإمارات)
await sendWhatsApp({
  instanceId: 'wsb1c2d3e4',
  accessToken: 'waship0002',
  number: '971501234567',
  message: 'رسالة من الجهاز الثاني'
});

حقل devices_limit في الباقة

القيمةالمعنى
1جهاز واحد فقط (الافتراضي)
2، 3، ...الحد الأقصى من الأجهزة المسموح بها
0غير محدود — تحدده الباقة المميزة

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

أأضف في .env

.env
WA_GATEWAY_URL=https://waship.prmgtk.com
WA_GATEWAY_INSTANCE_ID=ws3f9a2c1d
WA_GATEWAY_ACCESS_TOKEN=a3f9c2d1e4b5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1

بأضف في config/services.php

PHP
'wa_gateway' => [
    'base_url'     => env('WA_GATEWAY_URL', 'https://waship.prmgtk.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://waship.prmgtk.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://waship.prmgtk.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){ showQR(res.b.qr); 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();
// لربط جهاز آخر: غيّر قيمتَي IID و TOKEN للجهاز المطلوب
})();
</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 أيام تجربة مجانية

🚀 ابدأ مجاناً
WASHIP — منصة إرسال رسائل واتساب