Kirim pesan dari nomor
Peringatan Risiko Banned WhatsApp
- Melanggar ToS WhatsApp — nomor bisa di-banned kapan saja, apalagi kalau kirim massal ke nomor yang belum pernah chat Anda.
- Nomor baru + blast = cepat kena banned. Untuk follow-up ke kontak existing (yang sudah pernah interaksi) risikonya jauh lebih rendah.
🔥 Hot
dikirimi , balas ≤ 3 hari — prioritas closing
🌤️ Warm
dikirimi , interaksi ≤ 30 hari — nurture
😶 Passive
dikirimi , belum membalas
❄️ Cold
masuk , belum pernah dikirimi — re-engage
⛔ Lost
dikirimi , berhenti langganan
Aktivitas Pesan
Status Follow-up
Distribusi Jam Pengiriman
Segmen Tag Customer
💬 Inbox = daftar percakapan (1 baris per kontak, pesan terbaru + status belum dibaca) — untuk membalas chat masuk. Beda dengan Pesan yang menampilkan log tiap pesan keluar/masuk.
Total percakapan
Leads
hot / warm / passive / cold
Belum dibaca
Pesan masuk (total)
Pesan dibalas (total)
hari ini
Total customer
baru hari ini
Leads
hot / warm / passive / cold
Aktif
bisa di-follow-up
Berhenti Langganan
Reply rate
retensi balasan
| Nama & Nomor | WA | Tag | Follow-up | Balas | Status | Aktivitas | Aksi |
|---|---|---|---|---|---|---|---|
|
|
— | ||||||
| Belum ada data. | |||||||
📋 Pesan = log audit tiap pesan keluar & masuk (waktu, arah, status kirim, sumber: manual/API/AI) — untuk melacak & filter riwayat. Untuk membalas chat, gunakan Inbox.
Pesan keluar
Pesan masuk
Delivery rate
berhasil terkirim
Total di halaman
sesuai filter
| Arah | Kontak | Pesan | Waktu |
|---|---|---|---|
| Belum ada pesan. | |||
Total
Pending
Terkirim
Dibalas
Gagal
Jatuh tempo
antre kirim
| Kontak | Template | Jadwal | Status | Percobaan | Aksi |
|---|---|---|---|---|---|
|
|
|||||
| Belum ada follow-up. | |||||
Rangkaian follow-up otomatis bertahap (mis. H+1, H+3, H+7); tiap langkah terkirim sesuai jeda. Berhenti otomatis saat customer membalas. Untuk memakainya: Enroll customer ke sequence (dari kartu di bawah, halaman Customer, atau drawer customer).
Buat sequence dengan AI
Nama:
Total sequence
Enrollment aktif
Total langkah
- ·
- Belum ada langkah.
Gunakan placeholder {{name}}, {{phone}}.
Total template
Dipakai di sequence
Halaman
Pengguna login via Google SSO. Akun baru otomatis role guest. Atur role tiap pengguna di sini; super-admin utama (email di env) tak bisa diubah/dihapus.
Total pengguna
baru per 7 hari
Aktif
bisa login
Nonaktif
akses dicabut
Online 24 jam
login terkini
| Pengguna | Role | Akun WhatsApp | Status | Login terakhir | Aksi |
|---|---|---|---|---|---|
|
(Anda)
|
🔒 |
semua akun (super)
—
Belum ada akun WhatsApp — klik untuk menautkan. |
— | ||
| Belum ada pengguna. | |||||
Ganti role
Buat role custom dengan izin view/write per modul fitur, lalu terapkan ke pengguna.
Riwayat percobaan login (berhasil & gagal).
Total login
email unik
Berhasil
sesi terautentikasi
Gagal
percobaan ditolak
Aktivitas terkini
24 jam · per 7 hari
| Waktu | Hasil | IP | Perangkat | |
|---|---|---|---|---|
| Belum ada aktivitas. | ||||
Asisten & analis CRM bertenaga AI. Tanya apa saja soal data CRM, minta analisis, atau draft balasan.
CLAUDE_API_KEY dan/atau OPENAI_API_KEY di .env, lalu restart.
🔥 Hot
balas ≤ 3 hari — prioritas closing
🌤️ Warm
interaksi ≤ 30 hari — nurture
😶 Passive
sudah dikirimi, tidak membalas
❄️ Cold
belum pernah dikirimi pesan
⛔ Lost
berhenti langganan
⚠️ Kuota / kredit AI habis
Provider menolak permintaan (kuota/billing). Top-up kredit atau ganti provider di Pengaturan AI.
Asisten CRM DRW
Punya akses ringkasan CRM real-time. Coba salah satu:
Riwayat dibagi per akun WhatsApp. "Bersihkan" hanya mengosongkan tampilan; "Hapus" permanen untuk semua user akun.
Analisis Expert
Auto-reply pesan masuk
AI membalas otomatis saat customer chat. Mode auto mengirim langsung — gunakan hati-hati (risiko banned). Mode draft menyimpan saran untuk ditinjau di Inbox.
Gabungan auto-reply + follow-up + manual + agent. Tetap (proteksi banned) — tak bisa diubah dari sini.
Bot menunggu acak – detik sebelum mengirim (tetap, untuk keamanan anti-ban).
AI personalisasi follow-up
Scheduler pakai AI menyusun ulang pesan follow-up per customer (lebih personal). Template jadi panduan; gagal AI → pakai template asli.
🤖 Agent Otonom
Agent CRM yang berpikir multi-langkah, membaca data, lalu mengusulkan rencana aksi. Eksekusi selalu butuh persetujuan Anda & tunduk anti-ban.
Rencana aksi (centang untuk disetujui):
Hasil eksekusi:
Riwayat agent
Pilih AI & model default (hemat / medium / expert) yang dipakai di semua fitur AI, lalu atur otomasi. Model hemat cocok untuk testing.
Model default (dipakai semua modul AI)
Model per tier (lanjutan)
Harga token (referensi)
USD per 1 juta token (input / output) — info dari provider untuk estimasi biaya.
·
in · out
Provider AI custom
Pilih provider (OpenAI-compatible) — URL & model sudah otomatis. Anda cukup isi API key, selesai.
Lanjutan: URL & model per tier (default sudah terisi)
Belum ada. Pilih dari dropdown “+ Tambah provider…” di atas.
Aturan perilaku pengiriman yang menekan risiko nomor diblokir WhatsApp. Setiap aturan bisa dimatikan/dinyalakan dan berlaku langsung tanpa restart.
Di atas tahap terakhir, plafon penuh /hari berlaku.
Plafon harian efektif per nomor
Batas teknis
Diatur lewat .env (butuh restart), ditampilkan di sini sebagai acuan.
Plafon penuh
Rate
Cooldown kontak
Ketiganya selalu ditegakkan pada semua pengiriman. Jam kirim tidak ada di sini karena baru berlaku bila aturan Batasi jam kirim di atas dinyalakan.
Basis pengetahuan produk & FAQ. Dipakai AI sebagai acuan saat menjawab / draft balasan agar akurat.
Katalog Produk DRW Skincare
produk (sinkron dari drwrnd) · dipakai AI otomatis · terakhir
| Belum ada produk tersinkron. |
Tambah entri dari URL
Isi URL — server otomatis mendeteksi format JSON (API) atau HTML (halaman web), mengambil isinya, lalu menyimpannya ke database sebagai bahan AI.
Monitoring semua aktivitas kirim ke server WhatsApp: Integration API (server lain) & internal (follow-up, balasan, auto-reply, test).
Total
per 24 jam
Terkirim
Sampai/Dibaca
/
Dibalas
Gagal
Integration/Internal
/
pengirim
| Waktu | Kanal | Pengirim | Tujuan | Pesan | Status | |
|---|---|---|---|---|---|---|
|
Payload / Params — Tak ada payload. Payload/params hanya untuk kanal Integration (panggilan API server-ke-server). Ini aktivitas internal. WA msg id: IP: Response — Tak ada response body (aktivitas internal, bukan HTTP eksternal). Status kirim ada di kolom Status. |
||||||
| Belum ada aktivitas. | ||||||
Panduan integrasi server-to-server: kirim follow-up WhatsApp dari aplikasi lain melalui server ini, dengan pengirim = nomor yang tertaut ke email (role). Aktivitas terekam di Log Aktivitas.
Metode GET atau POST (JSON). Alias param: e|email_enc, phone|to, text|message, account (opsional bila email tertaut >1 nomor).
Cara kerja & keamanan
- Aplikasi lain login Google SSO yang sama → dapat email user.
- Aplikasi mengenkripsi email (AES-256-GCM) dengan shared secret yang sama (
INTEGRATION_SECRET), menghasilkan token. - Panggil endpoint dengan token sebagai param
e(bukan token sesi). - Server ini mendekripsi → cek email tertaut ke nomor WA tersambung → jika ya, kirim & catat. Token tidak memuat hak akses: izin diambil dari role user, dan cakupan nomor dari tautan akun di modul Pengguna (nomor yang dibuat sendiri oleh user otomatis tertaut; super-admin = semua nomor).
- Token punya masa berlaku (anti-replay).
Batas & aturan anti-ban
Endpoint ini kanal otomatis, jadi tunduk pada SEMUA aturan di Pengaturan Anti-ban. Status di bawah dibaca langsung dari pengaturan aktif.
- • Maks pesan/menit per nomor (selalu)
- • Cooldown detik ke kontak yang sama (selalu)
- • Kontak opt-out ditolak (selalu)
- • Delay manusiawi tiap kirim (selalu)
- •
Plafon harian efektif per nomor
:
Ditolak → respons memuat rule (alasan tepatnya). 429 = coba lagi nanti (ada Retry-After), 409 = jangan diulang tanpa perbaikan.
Daftar endpoint
Semua memakai otentikasi yang sama (?e=<token>) dan otomatis dibatasi ke nomor yang tertaut ke email tersebut. Param account (id atau nomor) opsional untuk mempersempit ke satu nomor; wajib bila email tertaut ke >1 nomor pada endpoint kirim/QR.
| Endpoint | Izin | Kegunaan |
|---|---|---|
| GET|POST /api/send | inbox/followups write | Kirim pesan. Param: phone, text, account. |
| GET /api/accounts | connection view | Daftar nomor + status: connected, hasQR, idle, dan history = progres impor riwayat setelah tersambung (phase waiting→syncing→saving→done, percent, received/saved/contacts). |
| GET /api/qr | connection write | Barcode pairing untuk ditampilkan di server lain. qr = data URL PNG, langsung dipakai <img src>. Panggil ulang tiap ±3 dtk sampai connected:true. |
| POST /api/accounts | connection write | Tambah nomor: buat akun WA baru (name), otomatis tertaut ke email pemanggil, balasan memuat QR pertama; lanjut polling /api/qr?account=. |
| POST /api/accounts/logout | connection write | Putus nomor (logout WhatsApp); akun & riwayat tetap, bisa dipasangkan ulang. Param: account. |
| POST /api/accounts/delete | connection write | Hapus nomor + akun & riwayatnya, wajib confirm=1; akun utama tak bisa dihapus. |
| GET /api/contacts | customers view | Daftar kontak + message_count & last_message_at. Param: search, limit (maks 200), offset. |
| GET /api/avatar | customers view | Foto profil satu kontak (phone/contact_id); ditarik ulang bila cache > 1 hari atau refresh=1. /api/contacts juga sudah memuat avatar_url absolut. |
| GET /api/media | inbox view | URL berkas media pesan (id pesan). Diunduh dari WhatsApp saat pertama diminta lalu di-cache. /api/messages memuat media_type/mime/filename/url. |
| GET /api/messages | inbox view | Riwayat pesan. Tanpa phone = semua percakapan; dengan phone = riwayat satu kontak. Polling pakai since_id (balikan last_id), atau since/direction. |
| GET /api/stats | dashboard view | Statistik Ringkasan per nomor akun + total: customer, pesan keluar/masuk (outPeriod/inPeriod sesuai range), follow-up, rates (delivery/reply/opt-out), lead hot/warm/passive/cold/lost dari kontak yang dikirimi dalam periode. Param: range (day|week|month|year|all), account, include (timeseries,funnel,hourly,tags). |
| GET /api/stream | inbox view | Notifikasi realtime (SSE). Event pesan masuk/keluar, perubahan centang, dan type:'history' (progres impor riwayat), sudah tersaring per nomor. |
Endpoint tulis — param boleh di query atau body JSON; token e ikut di dalamnya. Kunci name bersifat upsert. | ||
| POST /api/contacts | customers write | Tambah / perbarui nomor. Param: phone (wajib), name, tags, meta, account. Respons 201 baru / 200 diperbarui. |
| GET /api/templates | templates view | Daftar template: global + milik nomor tertaut. |
| POST /api/templates | templates write | Buat / perbarui template. Param: name, body (wajib), scope private|global, account. |
| GET /api/sequences | sequences view | Daftar sequence beserta steps & hitungan enrollment. |
| POST /api/sequences | sequences write | Buat / perbarui sequence. Param: name, steps = [{ delay_hours, template_id|template_name|body_override }], account. Jeda antar langkah min. 24 jam. |
| POST /api/enroll | sequences write | Daftarkan nomor ke sequence. Param: sequence_id|sequence_name, contact_id(s) atau phone(s) (nomor baru dibuat otomatis). Opt-out masuk skipped. |
Endpoint baca & QR TIDAK memakai API key dashboard — jadi aplikasi lain tak perlu diberi akses penuh ke server ini.
Contoh: notifikasi pesan masuk & tampilkan barcode
// 1) NOTIFIKASI REALTIME (SSE) — pesan masuk langsung sampai ke server Anda
const es = new EventSource(`https://wa.drwapp.com/api/stream?e=${token}`);
es.onmessage = (ev) => {
const m = JSON.parse(ev.data);
if (m.direction === 'in') simpanKeInboxAnda(m); // { phone, name, body, account_id, at }
};
// 2) ATAU POLLING (lebih tahan putus) — simpan last_id sebagai kursor
let lastId = bacaKursorTersimpan() || 0;
setInterval(async () => {
const r = await fetch(`https://wa.drwapp.com/api/messages?e=${token}&since_id=${lastId}&direction=in`);
const d = await r.json();
for (const m of d.rows) simpanKeInboxAnda(m);
lastId = d.last_id; simpanKursor(lastId); // hanya yang BARU di panggilan berikutnya
}, 10000);
// 3) RIWAYAT SATU KONTAK (untuk halaman detail di aplikasi Anda)
const riwayat = await (await fetch(
`https://wa.drwapp.com/api/messages?e=${token}&phone=628123456789&limit=100`)).json();
// 4) STATISTIK PER NOMOR (monitoring & evaluasi) — rumus sama dgn kartu Ringkasan
const st = await (await fetch(
`https://wa.drwapp.com/api/stats?e=${token}&range=month&include=timeseries`)).json();
for (const a of st.accounts) // + st.total = konsolidasi semua nomor
console.log(a.phone, a.messages.outPeriod, 'terkirim,', a.messages.inPeriod, 'masuk,', a.rates.replyRate + '% membalas', a.leads);
// 5) TAMPILKAN BARCODE KONEKSI DI SERVER LAIN
async function tampilkanQR(account) {
const d = await (await fetch(`https://wa.drwapp.com/api/qr?e=${token}&account=${account}`)).json();
if (d.connected) return tampilkanStatus('Nomor sudah tersambung ✅');
if (d.qr) document.querySelector('#qr').src = d.qr; // data URL PNG, langsung tampil
setTimeout(() => tampilkanQR(account), 3000); // QR berganti berkala
}
Token berumur pendek (). Untuk SSE/polling jangka panjang, generate ulang token di server Anda sebelum tiap koneksi/permintaan baru.
Uji cepat: generate token
Hanya untuk uji coba: buat token untuk email tertentu agar bisa mencoba endpoint tanpa menulis kode enkripsi. Di produksi, server lain membuat token sendiri dengan INTEGRATION_SECRET. Dibatasi ke super-admin karena siapa pun yang bisa membuat token bisa bertindak atas nama email tersebut.
Contoh: enkripsi email & kirim (Node.js)
import crypto from 'node:crypto';
const SECRET = process.env.INTEGRATION_SECRET; // SAMA dgn server WA
const key = crypto.createHash('sha256').update(SECRET).digest();
function encryptEmail(email) {
const iv = crypto.randomBytes(12);
const c = crypto.createCipheriv('aes-256-gcm', key, iv);
const payload = Buffer.from(JSON.stringify({ e: email.toLowerCase(), t: Math.floor(Date.now()/1000) }));
const ct = Buffer.concat([c.update(payload), c.final()]);
return Buffer.concat([iv, c.getAuthTag(), ct]).toString('base64url');
}
const token = encryptEmail(req.session.user.email); // email user yg login SSO
const url = `https://wa.drwapp.com/api/send?e=${token}`
+ `&phone=628123456789&text=${encodeURIComponent('Halo, ini follow-up dari kami')}`;
const r = await fetch(url);
const data = await r.json();
if (r.ok) {
console.log('terkirim:', data.wa_message_id); // { ok, from, to, wa_message_id }
} else if (r.status === 429) {
// DITAHAN SEMENTARA (rate_menit | cooldown_kontak | daily_cap | warmup |
// pesan_identik | jam_kerja). Jadwalkan ulang di antrean Anda — JANGAN
// retry beruntun, itu justru menaikkan risiko nomor kena banned.
const jeda = Number(r.headers.get('retry-after') || data.retryAfterSec || 60);
console.warn(`ditahan (${data.rule}), coba lagi ${jeda} detik lagi`);
await antrean.jadwalkanUlang({ phone, text, setelahDetik: jeda });
} else if (r.status === 409) {
// DITOLAK PERMANEN. Mengulang dgn isi & tujuan yang sama akan ditolak lagi:
// kontak_dingin -> nomor belum pernah chat; jangan hubungi duluan
// link_pesan_pertama -> kirim perkenalan tanpa link dulu
// opt_out -> kontak berhenti langganan; hormati, jangan kirim
console.error(`ditolak (${data.rule}): ${data.error}`);
await antrean.batalkan({ phone, alasan: data.rule });
} else {
// 400 param kurang | 401 token salah/kadaluarsa | 403 email tak berizin
// 503 integrasi nonaktif
console.error(`gagal ${r.status}: ${data.error}`);
}
Contoh: PHP
<?php
$secret = getenv('INTEGRATION_SECRET');
$key = hash('sha256', $secret, true);
$iv = random_bytes(12);
$payload = json_encode(['e' => strtolower($email), 't' => time()]);
$tag = '';
$ct = openssl_encrypt($payload, 'aes-256-gcm', $key, OPENSSL_RAW_DATA, $iv, $tag);
$token = rtrim(strtr(base64_encode($iv.$tag.$ct), '+/', '-_'), '=');
$url = "https://wa.drwapp.com/api/send?e=$token&phone=628123456789&text=".urlencode('Halo');
// PENTING: tanpa ignore_errors, file_get_contents() mengembalikan false pada
// 4xx sehingga alasan penolakan (rule) tidak pernah terbaca.
$ctx = stream_context_create(['http' => ['ignore_errors' => true, 'timeout' => 20]]);
$body = file_get_contents($url, false, $ctx);
$code = (int) substr($http_response_header[0], 9, 3);
$res = json_decode($body, true);
if ($code === 200) {
echo "terkirim: ".$res['wa_message_id'];
} elseif ($code === 429) {
// Ditahan sementara -> jadwalkan ulang, jangan retry beruntun.
$jeda = $res['retryAfterSec'] ?? 60;
error_log("ditahan ({$res['rule']}), ulangi {$jeda} detik lagi");
antrean_jadwalkan_ulang($phone, $text, $jeda);
} elseif ($code === 409) {
// Ditolak permanen: kontak_dingin | link_pesan_pertama | opt_out.
// Perbaiki dulu isi/tujuannya — mengulang sama saja akan ditolak lagi.
error_log("ditolak ({$res['rule']}): {$res['error']}");
antrean_batalkan($phone, $res['rule']);
} else {
error_log("gagal {$code}: ".($res['error'] ?? $body));
}
Kode respons
| 200 | { ok:true, from, to, wa_message_id } — terkirim & tercatat |
| 400 | Param kurang (e/phone/text) |
| 401 | Token tidak valid / secret salah / kadaluarsa |
| 403 | Email tidak terdaftar / tidak tertaut nomor / tanpa izin |
| 409 | Ditolak permanen — nomor tak tersambung / >1 nomor (sertakan account) / rule: opt_out, kontak_dingin, link_pesan_pertama. Jangan diulang dengan isi yang sama. |
| 429 | Ditahan sementara — rule: rate_menit, cooldown_kontak, daily_cap, warmup, pesan_identik, jam_kerja. Coba lagi sesuai Retry-After/retryAfterSec. |
| 503 | Integration API belum diaktifkan |
Kelola beberapa nomor WhatsApp (multi-sesi). Tiap nomor punya data & ringkasan sendiri; gabungan lihat di Semua Akun.