ضمّن شات مباشر عبر upuah.com بسكربت CDN واحد، أو نادِ API v1 من سيرفرك. الـ Widget آمن للمتصفح. مفتاح sesh_ للشات والتذاكر من الباك إند.

نظرة عامة

لـ Upuah سطحان: ويدجت الشات عبر CDN للزائر على موقعك، وواجهة السيرفر بمفتاح sesh_ للمحادثات والتذاكر من الباك إند.

القاعدة: https://upuah.com/api/v1 · الـ CDN: https://upuah.com

لا تضع مفتاح sesh_ في كود المتصفح. محمّل الـ embed يستخدم رمز emb_ عامًا ومقيّدًا بـ allowed origins.

ويدجت الشات (CDN)

صمّم الويدجت من Dashboard → Integrations → Widget (الألوان، التحية، أيقونة الإطلاق، المواقع المسموحة). الصق السكربت قبل </body>.

مسار الزائر: الاسم → الموبايل → «سيتم ربطك بوكيل» → حالة pending حتى Accept من الـ Inbox → رسالة انضمام الوكيل → شات مفتوح. Close ينهي المحادثة للطرفين.

كل Integration له محمّل emb_… فريد. النواة المشتركة: https://upuah.com/cdn/widget.js

سكربت التضمين

<script src="https://upuah.com/cdn/embed/emb_xxxxxxxx.js" async></script>

واجهة الودجت (آمنة للمتصفح)

بدون سر سيرفر. المسارات تحت /api/v1/widget/{embed_key}/… وتحترم allowed_origins من إعدادات الويدجت.

GET /config — الثيم والتحية والقناة الافتراضية. GET /auto-replies — الأسئلة الشائعة. POST /conversations — بدء بالاسم والموبايل (pending). GET …/messages — جلب الحالة والرسائل (مع can_chat). POST …/messages — رسالة الزائر (فقط عندما تكون الحالة open).

بدء شات (ويدجت)

POST https://upuah.com/api/v1/widget/{embed_key}/conversations
Content-Type: application/json
Accept: application/json

{
  "channel_id": 1,
  "name": "Alex Guest",
  "phone": "+971501234567"
}

جلب الرسائل

curl https://upuah.com/api/v1/widget/{embed_key}/conversations/{uuid}/messages \
  -H "Accept: application/json" \
  -H "Origin: https://your-site.example"

مصادقة السيرفر

طلبات السيرفر تستخدم مفتاح التكامل (sesh_…) الذي يُنشأ عند إضافة Integration. المفتاح مربوط بمستأجر واحد وتكامل واحد.

أرسله كـ Bearer أو عبر X-Sesh-Key. دوّر المفاتيح من Dashboard → Integrations.

Authorization: Bearer sesh_xxxxxxxx
X-Sesh-Key: sesh_xxxxxxxx
Accept: application/json

القنوات

أنشئ قناة نشطة واحدة على الأقل في الداشبورد (مثل الدعم الفني أو المبيعات) قبل الشات أو التذاكر.

الويدجت يستخدم القناة الافتراضية من إعداداته (أو channel_id في الطلب). التذاكر تستخدم قناة التذاكر الافتراضية من الإعدادات ما لم تمرّر channel_id.

واجهة الشات المباشر (سيرفر)

نفس الـ Inbox مثل الويدجت، لكن من باك إندك بمفتاح sesh_. تُفتح كمحادثة open (وليس مسار pending الخاص بالويدجت).

POST /api/v1/conversations — مطلوب: channel_id و name و subject وإما إيميل أو موبايل. اختياري: message لأول رسالة.

GET /api/v1/conversations/{uuid}/messages — قائمة الرسائل. POST …/messages — رسالة زائر. POST …/close — إغلاق.

curl -X POST https://upuah.com/api/v1/conversations \
  -H "Authorization: Bearer sesh_xxx" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "channel_id": 1,
    "name": "Nora",
    "email": "nora@example.com",
    "subject": "مشكلة الدفع",
    "message": "زر الدفع لا يعمل على الموبايل."
  }'

الرسائل والحالة

محادثات الويدجت: pending → open (بعد Accept) → closed. الزائر لا يرسل حتى open (can_chat: true).

عند التحويل تصبح الحالة transferred وتُرفض الرسائل على الـ uuid القديم. اعرض رسالة النظام وافتح الـ uuid الجديد من transferred_to.

curl https://upuah.com/api/v1/conversations/{uuid}/messages \
  -H "Authorization: Bearer sesh_xxx" \
  -H "Accept: application/json"

الردود التلقائية

تُدار من Dashboard → Auto replies. تُرجع للويدجت (إن كانت مفعّلة) وعبر GET /api/v1/auto-replies بمفتاح السيرفر.

curl https://upuah.com/api/v1/auto-replies \
  -H "Authorization: Bearer sesh_xxx" \
  -H "Accept: application/json"

واجهة التذاكر

منفصلة عن الشات المباشر. للتذاكر غير المتزامنة والمرفقات والردود المترابطة — وليست ويدجت التواصل.

POST /api/v1/tickets (multipart للمرفقات). مطلوب: name و subject و body وإيميل أو موبايل. اختياري: channel_id و attachments[].

GET /api/v1/tickets/{uuid} · POST /api/v1/tickets/{uuid}/replies

curl -X POST https://upuah.com/api/v1/tickets \
  -H "Authorization: Bearer sesh_xxx" \
  -F "name=Omar" \
  -F "email=omar@example.com" \
  -F "subject=فاتورة" \
  -F "body=الرابط لا يعمل" \
  -F "attachments[]=@/path/file.pdf"

الويب هوك

يمكن ضبط Webhook URL عند إنشاء التكامل. تحقق من X-Sesh-Signature = HMAC SHA-256 لجسم JSON الخام بسر الويب هوك. X-Sesh-Event يوضح اسم الحدث.

الأحداث: conversation.pending و conversation.accepted و message.created و conversation.closed و conversation.transferred و ticket.created و ticket.replied.

{
  "event": "message.created",
  "created_at": "2026-08-25T12:00:00+00:00",
  "data": {
    "conversation_uuid": "...",
    "message_uuid": "...",
    "body": "جارٍ المراجعة",
    "sender_type": "agent"
  }
}

التحقق من التوقيع (Node)

import crypto from 'crypto';

function verifyUpuahWebhook(rawBody, signatureHeader, secret) {
  const digest = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(digest),
    Buffer.from(signatureHeader),
  );
}

الربط بـ JavaScript

لواجهات مخصصة على السيرفر (Node) أو بروكسي باك إند. للزوار على الموقع فضّل ويدجت الـ CDN.

من المتصفح نادِ باك إندك الذي يحتفظ بالمفتاح — لا تضع sesh_ في الفرونت.

Node / باك إند

const API = 'https://upuah.com/api/v1';
const KEY = process.env.SESH_API_KEY;

async function startChat({ channelId, name, email, subject, message }) {
  const res = await fetch(`${API}/conversations`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${KEY}`,
      'Content-Type': 'application/json',
      Accept: 'application/json',
    },
    body: JSON.stringify({
      channel_id: channelId,
      name,
      email,
      subject,
      message,
    }),
  });

  if (!res.ok) throw new Error(await res.text());
  const { data } = await res.json();
  return data.uuid;
}

async function sendMessage(uuid, body) {
  const res = await fetch(`${API}/conversations/${uuid}/messages`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${KEY}`,
      'Content-Type': 'application/json',
      Accept: 'application/json',
    },
    body: JSON.stringify({ body }),
  });
  return res.json();
}

async function listMessages(uuid) {
  const res = await fetch(`${API}/conversations/${uuid}/messages`, {
    headers: {
      Authorization: `Bearer ${KEY}`,
      Accept: 'application/json',
    },
  });
  return res.json();
}

الربط بـ PHP

خزّن المفتاح في .env (مثلاً SESH_API_KEY). استخدم cURL أو Guzzle من السيرفر.

PHP cURL

$api = 'https://upuah.com/api/v1';
$key = getenv('SESH_API_KEY');

$payload = json_encode([
    'channel_id' => 1,
    'name' => 'Nora',
    'email' => 'nora@example.com',
    'subject' => 'مشكلة الدفع',
    'message' => 'زر الدفع لا يعمل.',
]);

$ch = curl_init($api.'/conversations');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer '.$key,
        'Content-Type: application/json',
        'Accept: application/json',
    ],
    CURLOPT_POSTFIELDS => $payload,
    CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);

الربط بـ Python

استخدم requests (أو httpx). احتفظ بالمفتاح في متغير بيئة على السيرفر.

Python requests

import os
import requests

API = 'https://upuah.com/api/v1'
KEY = os.environ['SESH_API_KEY']
HEADERS = {
    'Authorization': f'Bearer {KEY}',
    'Accept': 'application/json',
}

r = requests.post(
    f'{API}/conversations',
    headers={**HEADERS, 'Content-Type': 'application/json'},
    json={
        'channel_id': 1,
        'name': 'Nora',
        'email': 'nora@example.com',
        'subject': 'مشكلة الدفع',
        'message': 'زر الدفع لا يعمل.',
    },
)
r.raise_for_status()
uuid = r.json()['data']['uuid']

messages = requests.get(
    f'{API}/conversations/{uuid}/messages',
    headers=HEADERS,
).json()

الأخطاء

401 unauthenticated — مفتاح ناقص أو غير صالح.

403 forbidden — Origin غير مسموح للويدجت.

422 channel_required — أنشئ قناة / عيّن قناة التذاكر الافتراضية.

422 contact_required — أرسل إيميل أو موبايل (شات سيرفر / تذاكر).

422 Waiting for an agent to join — رسالة زائر أثناء pending.

422 validation — أخطاء الحقول في الـ JSON.