Dokumentasi API

Referensi lengkap REST API WA Client 1 — gateway WhatsApp multi-nomor dari PT Surya Digital Nusantara. Satu akun bisa mengelola beberapa nomor WhatsApp sekaligus, masing-masing dengan API key, riwayat chat, dan webhook sendiri yang terisolasi penuh dari nomor/akun lain.

Gambaran Umum

Base URL untuk seluruh endpoint di bawah ini:

https://pesan-client1.suryacloud.my.id

Setiap request dan response menggunakan JSON (content-type: application/json), kecuali endpoint upload media yang menerima multipart/form-data.

Model multi-nomor: satu akun (login via Google) dapat menghubungkan beberapa nomor WhatsApp. Setiap nomor punya API key sendiri, riwayat percakapan sendiri, dan konfigurasi webhook sendiri — tidak ada endpoint yang mengembalikan data lintas-nomor atau lintas-akun.

Mulai Cepat

  1. Login dengan akun Google — akun dibuat otomatis saat pertama kali login.
  2. Di halaman Nomor Saya, klik + Tambah Nomor dan beri nama.
  3. Salin API key yang ditampilkan — hanya muncul sekali saat itu juga.
  4. Buka dashboard nomor tersebut, scan QR dari WhatsApp di HP (Perangkat Tertaut → Tautkan Perangkat).
  5. Panggil endpoint di bawah menggunakan API key nomor tersebut.

Autentikasi

Endpoint pengiriman pesan (/api/send/*, /api/groups, /media/*) diautentikasi dengan API key per-nomor, dikirim lewat header x-api-key (atau parameter query ?key= jika header tidak memungkinkan, mis. embed <img>).

x-api-key: API_KEY_NOMOR_ANDA
Penting: API key hanya ditampilkan penuh satu kali — saat nomor dibuat atau saat Anda menekan "Rotate" di dashboard. Setelahnya hanya beberapa karakter awal yang terlihat. Simpan key di tempat aman (secret manager / env var), bukan di kode sumber.

Login dashboard (halaman web) menggunakan akun Google, terpisah sepenuhnya dari API key — API key tidak pernah digunakan untuk login ke dashboard, dan sebaliknya.

POST/api/send/text🔑 API key

Mengirim pesan teks ke nomor personal atau grup.

FieldTipeKeterangan
tostringNomor tujuan (mis. 628123456789) atau JID grup (...@g.us).
messagestringIsi pesan teks.
curl -X POST https://pesan-client1.suryacloud.my.id/api/send/text \
  -H "x-api-key: API_KEY_ANDA" \
  -H "content-type: application/json" \
  -d '{"to":"628123456789","message":"Halo dari WA Client 1"}'
const res = await fetch('https://pesan-client1.suryacloud.my.id/api/send/text', {
  method: 'POST',
  headers: { 'x-api-key': 'API_KEY_ANDA', 'content-type': 'application/json' },
  body: JSON.stringify({ to: '628123456789', message: 'Halo dari WA Client 1' }),
});
import requests

requests.post(
    'https://pesan-client1.suryacloud.my.id/api/send/text',
    headers={'x-api-key': 'API_KEY_ANDA'},
    json={'to': '628123456789', 'message': 'Halo dari WA Client 1'},
)

Response 200

{ "success": true, "messageId": "3EB0..." }
POST/api/send/media🔑 API key

Mengirim gambar, video, dokumen, atau audio. Terima file langsung (multipart/form-data) atau URL media yang sudah publik.

FieldTipeKeterangan
tostringNomor atau JID grup tujuan.
filefileUpload langsung (opsional jika mediaUrl diisi).
mediaUrlstringURL http(s) ke file media (opsional jika file diisi).
typestringimage / video / document / audio — wajib jika pakai mediaUrl, opsional (auto-deteksi dari mimetype) jika upload file.
captionstringOpsional, teks penyerta.
fileNamestringOpsional, nama file untuk dokumen.
curl -X POST https://pesan-client1.suryacloud.my.id/api/send/media \
  -H "x-api-key: API_KEY_ANDA" \
  -F "to=628123456789" \
  -F "file=@/path/ke/gambar.jpg" \
  -F "caption=Contoh gambar"
const form = new FormData();
form.append('to', '628123456789');
form.append('mediaUrl', 'https://contoh.com/gambar.jpg');
form.append('type', 'image');
await fetch('https://pesan-client1.suryacloud.my.id/api/send/media', {
  method: 'POST', headers: { 'x-api-key': 'API_KEY_ANDA' }, body: form,
});
GET/api/groups🔑 API key

Daftar grup WhatsApp yang diikuti nomor ini.

{ "groups": [ { "id": "1234-5678@g.us", "subject": "Tim Support", "participants": 12 } ] }

Webhook

Dikelola dari halaman Webhook di dashboard nomor Anda (bukan lewat API key). Satu nomor bisa punya lebih dari satu tujuan webhook sekaligus — misalnya satu ke Google Apps Script untuk otomasi, satu lagi ke server OTP login — setiap event dikirim ke semua endpoint yang aktif secara paralel dan independen. Tiap endpoint punya URL dan secret HMAC-nya sendiri, jadi merotasi atau menghapus satu integrasi tidak memengaruhi yang lain.

Event yang Dikirim

EventKapan Terjadi
message.incomingAda pesan masuk (personal atau grup).
message.statusStatus pesan keluar berubah (sent / delivered / read / failed).
identity.mergedKontak yang sebelumnya dikenali lewat @lid berhasil diketahui nomor HP aslinya (lihat penjelasan LID di bawah) — pakai ini untuk menggabungkan kontak/thread lama Anda.
device.connectedNomor berhasil terhubung ke WhatsApp.
device.disconnectedKoneksi terputus (cek field needsQrScan).

Setiap payload otomatis disisipi numberId dan phoneNumber milik nomor WA Client1 Anda sendiri (bukan lawan bicara) — jadi satu URL webhook bisa dipakai untuk beberapa nomor sekaligus dan tetap bisa dibedakan asalnya. Untuk identitas pengirim/lawan bicara, selalu pakai chatId/from, bukan phoneNumber di level atas ini.

{
  "event": "message.incoming",
  "chatId": "628123456789@s.whatsapp.net",
  "from": "628123456789@s.whatsapp.net",
  "isGroup": false,
  "isFromMe": false,
  "type": "text",
  "text": "Halo, ada info?",
  "numberId": "b3f1...",
  "phoneNumber": "6281234567890"
}
Penting — identitas pengirim bisa berupa LID, bukan nomor HP. Untuk sebagian kontak (fitur privasi WhatsApp terbaru), chatId/from pada message.incoming bisa berisi identitas WhatsApp internal berformat <angka-acak>@lid alih-alih <nomor-hp>@s.whatsapp.net — biasanya untuk kontak yang belum pernah mengirim lewat nomor HP aslinya dan belum tersimpan di address book nomor WA Client1 Anda. Ini bukan bug pengiriman: WhatsApp memang tidak selalu membocorkan nomor HP asli kontak seperti itu di level protokol, bahkan aplikasi WhatsApp resmi si pengirim pun menampilkannya sebagai kontak terpisah sampai nomornya "ketemu".

WA Client1 otomatis meresolusi @lid → nomor HP asli begitu nomornya diketahui (lewat sinkronisasi kontak, atau kontak tsb membagikan nomornya), lalu memakai nomor asli itu untuk seluruh pesan berikutnya. Kalau resolusi ini terjadi setelah Anda sudah menerima satu/lebih message.incoming dengan chatId ber-@lid, Anda akan menerima event identity.merged berisi oldChatId (yang lama, @lid) dan newChatId (nomor HP asli) — pakai ini untuk menggabungkan kontak/thread yang sempat tercatat terpisah di sisi Anda. Jangan asumsikan chatId/from selalu berformat @s.whatsapp.net, dan jangan pakai field phoneNumber di level atas sebagai pengganti — field itu identitas nomor WA Client1 Anda sendiri, bukan lawan bicara.

Contoh payload message.status — perhatikan nama field-nya chatId, bukan to:

{
  "event": "message.status",
  "messageId": "3EB0...",
  "chatId": "628123456789@s.whatsapp.net",
  "status": "delivered",
  "timestamp": 1786450000,
  "numberId": "b3f1...",
  "phoneNumber": "6281234567890"
}

Contoh payload identity.merged:

{
  "event": "identity.merged",
  "oldChatId": "44294803030187@lid",
  "newChatId": "628123456789@s.whatsapp.net",
  "numberId": "b3f1...",
  "phoneNumber": "6281234567890"
}

Verifikasi Signature

Setiap request webhook menyertakan header x-webhook-signature berisi HMAC-SHA256 dari body mentah, ditandatangani dengan secret milik endpoint tujuan itu sendiri (beda dari API key, dan beda per endpoint kalau Anda punya lebih dari satu — lihat halaman Webhook di dashboard).

const crypto = require('crypto');

function isValid(rawBody, header, secret) {
  const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header));
}
import hmac, hashlib

def is_valid(raw_body: bytes, header: str, secret: str) -> bool:
    expected = 'sha256=' + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, header)
Selalu verifikasi signature sebelum memproses payload — jangan percaya isi numberId/phoneNumber di body tanpa verifikasi terlebih dahulu.

Rate Limit

Endpoint /api/send/* dibatasi 20 pesan per menit per nomor (bisa berbeda per deployment) untuk mengurangi risiko deteksi otomatisasi oleh WhatsApp. Response melebihi batas mengembalikan status 429 dengan header retry-after.

Kode Error

StatusArti
400Parameter request tidak valid atau kurang.
401API key tidak ada / tidak valid, atau sesi login tidak valid.
404Resource tidak ditemukan (termasuk mengakses nomor yang bukan milik Anda).
409Konflik — mis. batas maksimum jumlah nomor per akun tercapai.
429Melebihi rate limit.
500Kesalahan tak terduga di server.
{ "error": "pesan penjelasan singkat" }