D
API Reference

Messaging API

Endpoint messaging — POST /api/send-message (text), /api/send-media (image/video/document/audio/link), /api/send-location, /api/send-broadcast. Anti-ban presence simulation. pesan_id, role, data wajib.

Endpoint messaging mengirim pesan keluar ke WhatsApp. Semua operasi memerlukan instance yang sudah CONNECTED.

POSThttp://localhost:5002/api/api/send-message
curl --request POST \
  --url http://localhost:5002/api/api/send-message

POST /api/send-message — Kirim teks

Handler: MessageController.sendText (src/controller/MessageController.ts:11)

Request fields

FieldWajibTipeCatatan
instance✅stringUUID sesi — harus CONNECTED
number✅stringNomor tujuan (628xxx) atau grup (<id>-<id>@g.us)
message✅stringIsi pesan
pesan_id✅stringID pesan internal — diteruskan ke Socket.IO, bukan untuk kirim
role✅stringRole pengirim (cs, user, dll.) — diteruskan ke Socket.IO
data✅string|objectData tambahan (JSON string atau object) — diteruskan ke Socket.IO
quoted_raw_message❌string|objectRaw message untuk fitur reply (JSON string atau object)

Contoh request

json
{
  "instance": "0c1a968c-...",
  "number": "628123456789",
  "message": "Halo!",
  "pesan_id": "uuid-pesan",
  "role": "cs",
  "data": "{}",
  "quoted_raw_message": "{...}"
}

Response data

json
{
  "success": true,
  "message": "Sukses kirim pesan",
  "data": {
    "id": "3EB0...",
    "status": 1,
    "raw_message": "{\"key\":{...},\"message\":{...},\"messageTimestamp\":170000}",
    "number": "628123456789",
    "message_content": "Halo!"
  }
}

raw_message adalah bentuk minimal pesan terkirim — simpan nilai ini bila ingin memakainya sebagai quoted_raw_message saat membalas.

Anti-ban presence

Sebelum kirim, engine mensimulasikan presence:

  1. presenceSubscribe(formattedNumber)
  2. sendPresenceUpdate('composing', formattedNumber) — typing indicator
  3. Jeda 1 detik
  4. sendPresenceUpdate('paused', formattedNumber) — stop typing
  5. sock.sendMessage(...)

onWhatsApp validation

Untuk nomor personal (bukan grup), engine validasi nomor terdaftar di WhatsApp:

text
formatNumber(number) → jika bukan @g.us:
  sock.onWhatsApp(formattedNumber)
  jika !exists → throw "Nomor tujuan belum terdaftar Whatsapp"

quoted_raw_message — reply

Jika quoted_raw_message ada, di-parse (JSON string → object) dan dipakai sebagai options.quoted di sock.sendMessage. Timestamp Long object dinormalisasi.

Socket emit

Setelah kirim, engine emit sendmessage + sendmessage_bubble ke room instance:

json
{
  "id": "628123456789",
  "type": "sendmessage",
  "number": 0,
  "instance": "0c1a968c-...",
  "text": "uuid-pesan",
  "status": "sent",
  "role": "cs",
  "data": { ... },
  "timestamp": "2024-01-15T10:30:00.000Z"
}

POST /api/send-media — Kirim media / link preview

Handler: MessageController.sendMedia (src/controller/MessageController.ts:98)

Request fields

FieldWajibTipeCatatan
instance✅stringUUID sesi
number✅stringNomor tujuan
type✅stringimage / video / document / audio / link
url✅stringURL media (atau URL untuk link preview)
caption❌stringCaption (untuk image/video/document)
ptt❌booleantrue = voice note (khusus audio)
filename❌stringNama file (khusus document, default file.pdf)
pesan_id❌stringID pesan internal
role❌stringRole pengirim
data❌string|objectData tambahan
quoted_raw_message❌string|objectRaw message untuk reply

Contoh request

json
{
  "instance": "0c1a968c-...",
  "number": "628123456789",
  "type": "image",
  "url": "https://example.com/photo.jpg",
  "caption": "Lihat foto ini",
  "pesan_id": "msg-1",
  "role": "cs",
  "data": "{}"
}

Perilaku per tipe

typeCatatan
image / videoDikirim dengan caption
documentMimetype dipaksa application/pdf, nama default file.pdf
audioMimetype audio/mp4; ptt: true → voice note (presence jadi recording)
linkurl di-fetch metadatanya via link-preview-js, dikirim sebagai teks + preview

Validasi URL

Untuk image/video/document/audio, URL divalidasi lebih dulu via isMediaUrlValid:

ts
const response = await fetch(url, { method: 'HEAD', signal: AbortSignal.timeout(5000) });
return response.ok;  // 200-299

Jika tidak dapat diakses, request gagal tanpa mengirim presence:

plaintext
"Media URL tidak dapat diakses: <url>"

Response data

json
{
  "success": true,
  "message": "Sukses kirim pesan",
  "data": {
    "id": "3EB0...",
    "result": true,
    "status": true,
    "type": "image",
    "raw_message": "{...}",
    "url": "https://example.com/photo.jpg"
  }
}

POST /api/send-location — Kirim lokasi

Handler: MessageController.sendLocation (src/controller/MessageController.ts:201)

Request fields

FieldWajibTipeCatatan
instance✅stringUUID sesi
number✅stringNomor tujuan
latitude✅string|numberLatitude
longitude✅string|numberLongitude
quoted_raw_message❌string|objectDiparsing tapi diabaikan service

Contoh request

json
{
  "instance": "0c1a968c-...",
  "number": "628123456789",
  "latitude": "-6.200000",
  "longitude": "106.816666"
}

Response

json
{
  "success": true,
  "message": "Location sent",
  "data": { ...result.key }
}

POST /api/send-broadcast — Kirim ke banyak nomor

Handler: MessageController.sendBroadcast (src/controller/MessageController.ts:268)

Request fields

FieldWajibTipeCatatan
instance✅stringUUID sesi
number✅string|string[]Array nomor atau string dipisah koma
message✅stringIsi pesan

Contoh request

json
{
  "instance": "0c1a968c-...",
  "number": ["628111", "628222"],
  "message": "Promo hari ini!"
}

Response (1 nomor — objek tunggal)

json
{
  "success": true,
  "message": "Broadcast selesai diproses",
  "data": {
    "result": true,
    "id": "3EB0...",
    "number": "628111",
    "message": "Berhasil Terkirim"
  }
}

Response (>1 nomor — rekap)

json
{
  "success": true,
  "message": "Broadcast selesai diproses",
  "data": {
    "result": true,
    "count": 2,
    "success": 1,
    "failed": 1,
    "message": "Broadcast selesai diproses",
    "details": [
      { "result": true,  "id": "3EB0...", "number": "628111", "message": "Berhasil Terkirim" },
      { "result": false, "id": "",        "number": "628222", "message": "Nomor tujuan belum terdaftar Whatsapp" }
    ]
  }
}

Anti-ban delay

Untuk broadcast >1 nomor, ada jeda acak 3-5 detik antar pengiriman:

ts
const delayTime = Math.floor(Math.random() * 2000) + 3000;  // 3000-5000ms

Broadcast memanggil sendTextMessage per nomor — yang berarti setiap nomor juga mendapat presence simulation (composing → paused).

Catatan

  • sendContact sudah diimplementasi di MessageController.ts:249 tapi tidak didaftarkan di router — tidak dapat diakses
  • formatNumber() menormalkan input otomatis — lihat Conventions
  • Grup (deteksi: mengandung - atau panjang >15 digit) tidak divalidasi onWhatsApp
  • Presence simulation bisa gagal — ditangkap dengan try/catch, tidak menghentikan pengiriman

Langkah berikutnya