إرسال رسالة واتساب باستخدام Node.js
ترسل هذه الصفحة رسالة واتساب من Node.js بالدالة fetch المدمجة فيه، ثم تستقبل الرد في خادم HTTP صغير. لا شيء هنا يحتاج إلى حزمة من npm.
ما الذي تحتاجه
- حساب على Threadwire.
- رقم مربوط. في لوحة التحكم، اضغط «إضافة رقم» وامسح رمز QR بواتساب على الهاتف (الإعدادات ← الأجهزة المرتبطة). ثم انسخ معرّف الرقم من صفحة الرقم.
- مفتاح API. أنشئه من للمطورين ← مفاتيح API ← مفتاح جديد (للمسؤولين فقط).
- Node.js 18 أو أحدث. المثال وحدة ES: ملف
.mjs، أو"type": "module"فيpackage.json. ويقرأ المفتاح من متغير بيئة اسمهTHREADWIRE_KEY.
«الرقم» في Threadwire هو رقم واتساب واحد مربوط به. يُربط كجهاز، بالطريقة نفسها التي يُربط بها WhatsApp Web، فهذه ليست الواجهة الرسمية من Meta. صفحة WhatsApp API بدون موافقة Meta تشرح معنى ذلك.
أرسل الرسالة
أرسل الرسالة الأولى إلى نفسك. اكتب «مرحبًا» إلى رقمك المربوط من واتساب على هاتف آخر لك، ثم أرسل إلى ذلك الهاتف. لديك هاتف واحد فقط؟ ضع رقم الهاتف المربوط نفسه في to.
// Node.js 18 or later, in an ES module (.mjs, or "type": "module")
const response = await fetch('https://threadwire.net/api/v1/messages', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.THREADWIRE_KEY}`, 'Content-Type': 'application/json', Accept: 'application/json' },
body: JSON.stringify({ instance_id: 'YOUR_INSTANCE_ID', to: 'YOUR_PHONE', text: 'Hello from Threadwire' }),
});
if (!response.ok) throw new Error(await response.text());
const { data: message } = await response.json();
console.log(message.id, message.status);
Authorization: مفتاح API الخاص بك كرمز Bearer، ويُرسل مع كل طلب.instance_id: معرّف الرقم الذي نسخته.to: رقم ذلك الهاتف بالصيغة الدولية، مثل201012345678: رمز الدولة، بلا حاجة إلى+، وبلا صفر في البداية.text: نص الرسالة، حتى 4,096 حرفًا.
اقرأ رد الـ API
يصل الرد فورًا، ويأخذ المثال الرسالة من data:
202 {"data": {"id": "01K…", "status": "queued", "phone": "201012345678", "body": "Hello from Threadwire", "…": "…"}}
id: احتفظ به.GET /v1/messages/{id}يعيد الرسالة بحالتها في تلك اللحظة.status: القيمةqueuedتعني أن الرسالة قُبلت وهي في الانتظار حتى يأتي دورها. فما يعطيك إياهawaitرسالة في الانتظار، لا رسالة وصلت.phoneوbody: من تُرسل إليه الرسالة، ونصها.
الرسالة التي في الانتظار تُرسل كما يرسلها الإنسان. بعدها تنتقل status إلى sent ثم delivered ثم read، أو إلى failed مع السبب في error.
أنت كتبت أولًا، فهذه الرسالة رد، وتصل خلال ثوانٍ. أما الرسالة الأولى إلى من لم يراسل رقمك من قبل فهي أبطأ الأنواع. هذه الرسائل تُرسل متباعدة، ولها حد يومي، ولا تُرسل ليلًا، فدع الناس يكتبون أولًا. دليل كيف يحمي الإرسال رقمك فيه كل قاعدة بأرقامها.
استقبل الرد على رسالتك
من للمطورين ← الويب هوك (للمسؤولين فقط)، حدّد رابط الاستقبال لديك: عنوان عام يبدأ بـ https://. يبدأ سر التوقيع بـ whsec_، ويظهر عند حفظ الرابط. بعدها يُرسل كل رد وكل تغيّر في الحالة إلى رابط الاستقبال لديك بصيغة JSON:
{"id": "evt_01K…", "type": "message.received", "created_at": "2026-10-01T10:00:00+00:00",
"data": {"id": "01K…", "instance_id": "01K…", "phone": "201012345678", "body": "Hi!", "…": "…"}}
يصل الرد كحدث message.received، ويصل تحديث التسليم كحدث message.status.
كل حدث موقّع وفق مواصفة Standard Webhooks. خادم الاستقبال هذا، من دليل الويب هوك، كامل. يقرأ جسم الطلب الخام، ويتحقق من التوقيع، ويرد بـ 200 فورًا، ويتجاهل المكرر. ويستمع على المنفذ 3000.
// Node.js 18 or later, no packages. Run: THREADWIRE_WEBHOOK_SECRET=whsec_… node endpoint.mjs
import crypto from 'node:crypto';
import http from 'node:http';
const key = Buffer.from(process.env.THREADWIRE_WEBHOOK_SECRET.replace(/^whsec_/, ''), 'base64');
const handled = new Set(); // in production: your database or cache
http.createServer((req, res) => {
const chunks = [];
req.on('data', (chunk) => chunks.push(chunk));
req.on('end', () => {
// The raw body, exactly as it arrived: the signature covers these bytes.
const body = Buffer.concat(chunks);
const id = req.headers['webhook-id'];
const timestamp = req.headers['webhook-timestamp'];
// 1. Verify: sent in the last 5 minutes, and signed with your secret.
const expected = Buffer.from('v1,' + crypto.createHmac('sha256', key)
.update(`${id}.${timestamp}.`).update(body).digest('base64'));
const fresh = Math.abs(Date.now() / 1000 - Number(timestamp)) <= 300;
const signed = (req.headers['webhook-signature'] ?? '').split(' ').some((signature) => {
const given = Buffer.from(signature);
return given.length === expected.length && crypto.timingSafeEqual(given, expected);
});
if (!fresh || !signed) {
res.writeHead(401).end();
return;
}
// 2. Answer 200 at once, before any slow work.
res.writeHead(200).end();
// 3. Drop repeats: an event sent again keeps its webhook-id.
if (handled.has(id)) return;
handled.add(id);
const event = JSON.parse(body);
console.log(event.type);
if (event.type === 'message.received') {
console.log(`${event.data.phone}: ${event.data.body}`);
}
});
}).listen(3000);
اضغط «إرسال حدث تجريبي» في صفحة الويب هوك، فيُرسل حدث webhook.test إلى رابط الاستقبال لديك. ثم اكتب إلى رقمك المربوط من هاتف آخر: يصلك حدث message.received.
تستخدم Express؟ في دليل الويب هوك والأحداث الفحص نفسه في دالة واحدة.
من المفيد أن تعرف
- إعادة المحاولة آمنة مع ترويسة
Idempotency-Key. أضف'Idempotency-Key': 'order-1042-shipped'إلىheaders: أي نص فريد من عندك. إعادة المحاولة بالمفتاح نفسه تعيد الرسالة الأولى بدلًا من إرسال ثانية. - للخطأ
code. يرمي المثال نص الرد، وهو JSON. وفيهmessageبكلمات بسيطة وcodeثابت، مثلvalidation_failed، يعتمد عليه برنامجك. - أعد محاولة ما يمكن أن ينجح فقط. أعد محاولة
429و502و503، بعدRetry-Afterإن وُجد. أما401و403و404و422فتحتاج إصلاحًا أولًا. راجع ما الذي يعيد نظامك محاولته. - قد تصل الأحداث بغير ترتيبها. استخدم
created_atفي كل حدث، وأوقات الرسالة نفسها.
التالي
- إرسال الرسائل: الملفات والرسائل الصوتية والاستطلاعات وغيرها، كحقول في الطلب نفسه.
- الويب هوك والأحداث: كل الأحداث، وإعادة المحاولة، والجلب.
- مرجع الـ API: كل نقاط الاتصال، والأخطاء.
- الأدوات وأمثلة الكود: مجموعة Postman، وهذا الطلب بلغات أخرى.