# WhatsApp Gateway — Referensi API untuk Client

Dokumen ini untuk **developer aplikasi client** (mis. aplikasi sekolah) yang mengirim
pesan/tagihan lewat gateway.

- **Base URL:** `http://<host>:3600` (produksi contoh: `http://27.112.79.2:3600`)
- **Autentikasi:** setiap request menyertakan **API key client** di header
  `X-API-Key: <key>` (atau query `?apikey=<key>`). Key didapat dari admin/dashboard.
- Semua response berupa **JSON**.
- Versi interaktif: buka `/docs` di browser.

> **Prinsip:** aplikasi cukup **menitip** pesan (nomor tujuan + isi + lampiran). Gateway
> yang **memilih nomor pengirim sehat, mengatur ritme, mencoba ulang, dan melacak status**.
> Aplikasi **tidak** menentukan nomor pengirim.

---

## Alur singkat (disarankan)

```
1. POST /api/enqueue     → titip tiap tagihan (nomor + teks + PDF + client_ref)  → { message_id, status:"queued" }
2. (gateway mengirim otomatis, bergiliran antar nomor, dengan jeda)
3. POST /api/status      → cek hasil per client_ref                               → status tiap pesan
```

`client_ref` = kode unik milik Anda per pesan (mis. kode tagihan). Wajib dipakai agar:
- **tidak terkirim dobel** (kalau aplikasi mengulang request), dan
- bisa **melacak status** tanpa menyimpan `message_id`.

---

## 1. Titip pesan ke antrian

`POST /api/enqueue`  — **Content-Type: multipart/form-data**

| Field | Wajib | Keterangan |
|---|---|---|
| `to` | ✅ | Nomor tujuan. Format `08…`, `62…`, `+62…`, atau JID grup `…@g.us` |
| `text` | – | Isi pesan (pesan teks); atau caption bila ada `file` |
| `file` | – | Lampiran PDF/gambar |
| `caption` | – | Caption lampiran (kalau tidak diisi, `text` dipakai) |
| `as_image` | – | `true` bila lampiran dikirim sebagai gambar (default: dokumen) |
| `client_ref` | disarankan | Kode unik Anda per pesan (idempotensi + pelacakan) |

Wajib ada minimal salah satu: `text` atau `file`.

**Contoh — tagihan + PDF:**
```bash
curl -X POST http://27.112.79.2:3600/api/enqueue \
  -H "X-API-Key: <CLIENT_KEY>" \
  -F "to=08123456789" \
  -F "text=Tagihan SPP Juli 2026 a.n. Medina Humairah" \
  -F "client_ref=IU-SD-072026-00039" \
  -F "file=@/path/tagihan-medina.pdf"
```
**Response:**
```json
{ "message_id": 1201, "client_ref": "IU-SD-072026-00039", "status": "queued" }
```
Kalau `client_ref` sudah pernah dikirim:
```json
{ "message_id": 1201, "client_ref": "IU-SD-072026-00039", "status": "queued", "dedup": true }
```
(*tidak* dikirim ulang.)

**Contoh — pesan teks saja:**
```bash
curl -X POST http://27.112.79.2:3600/api/enqueue \
  -H "X-API-Key: <CLIENT_KEY>" \
  -F "to=08123456789" -F "text=Halo, ini pengingat." -F "client_ref=REM-001"
```

---

## 2. Cek status (polling)

`POST /api/status`  — **Content-Type: application/json**

Cek banyak `client_ref` sekaligus.
```bash
curl -X POST http://27.112.79.2:3600/api/status \
  -H "X-API-Key: <CLIENT_KEY>" -H "Content-Type: application/json" \
  -d '{ "refs": ["IU-SD-072026-00039","IU-SD-072026-00040"] }'
```
**Response:**
```json
{ "messages": [
  { "client_ref":"IU-SD-072026-00039", "status":"delivered", "sender":"628123456789",
    "recipient":"628...", "sent_at":"2026-07-04 10:14:09",
    "delivered_at":"2026-07-04 10:14:12", "read_at":null, "error":"" },
  { "client_ref":"IU-SD-072026-00040", "status":"queued", "sender":"" }
]}
```

### Arti status pesan
| status | arti | tindakan aplikasi |
|---|---|---|
| `queued` | menunggu giliran kirim | tunggu |
| `processing` | sedang diproses | tunggu |
| `sent` | diterima server WhatsApp (1 centang) | tunggu konfirmasi |
| `delivered` | **sampai ke HP penerima (2 centang)** | ✅ sukses |
| `read` | dibaca penerima | ✅ sukses (lebih dari delivered) |
| `undelivered` | belum sampai (penerima mungkin offline) | tunggu / tindak lanjut |
| `failed` | gagal dikirim (error) | bisa di-retry |
| `invalid` | nomor tujuan tidak terdaftar di WhatsApp | perbaiki nomor |

> **Definisi sukses = `delivered`** (atau `read`).

---

## 3. Ringkasan antrian

`GET /api/queue/summary`
```bash
curl -H "X-API-Key: <CLIENT_KEY>" http://27.112.79.2:3600/api/queue/summary
```
```json
{ "queued":12, "processing":1, "sent":2, "delivered":683, "read":40,
  "undelivered":3, "failed":1, "invalid":5 }
```

---

## 4. Riwayat pesan (opsional)

`GET /api/messages?status=&sender=&q=&limit=&offset=`
```bash
curl -H "X-API-Key: <CLIENT_KEY>" \
  "http://27.112.79.2:3600/api/messages?status=undelivered&limit=25&offset=0"
```
Response `{ "total": N, "messages": [ ... ] }` (25/halaman default).

---

## 5. Kirim ulang yang gagal (opsional)

- `POST /api/queue/retry-failed` → antrikan ulang **semua** pesan `failed`/`invalid` milik Anda.
  Response `{ "requeued": N }`.
- `POST /api/messages/{id}/retry` → antrikan ulang satu pesan.

---

## 6. Info & nomor pengirim (opsional)

| Endpoint | Fungsi |
|---|---|
| `GET /api/me` | Info client Anda (nama, jumlah & batas nomor) |
| `GET /api/senders` | Daftar nomor pengirim Anda + status koneksi & health |
| `GET /api/senders/{number}/groups` | Grup yang diikuti sebuah nomor (untuk kirim ke grup) |

Contoh isian `GET /api/senders`:
```json
[{ "number":"628123456789", "status":"connected", "health":"healthy",
   "daily_count":42, "max_per_day":150, "delivered":40, "undelivered":2 }]
```

> Pengelolaan nomor (tambah nomor/scan QR, atur kuota, pulihkan, hapus) umumnya
> dilakukan lewat **dashboard** (`/`), bukan dari aplikasi.

### Pengaturan pengiriman massal (jam kerja & interval)

| Endpoint | Fungsi |
|---|---|
| `GET /api/settings` | Ambil pengaturan client |
| `PUT /api/settings` | Ubah pengaturan client |

```json
{ "work_start": 7, "work_end": 21, "tz_offset": 7,
  "min_delay": 10, "max_delay": 20,
  "rate_max": 15, "rate_window_min": 30 }
```
- `work_start`/`work_end` = jam kerja (0–23). **Sama** (mis. 0 & 0) = **tanpa batasan** (24 jam).
- `tz_offset` = zona waktu (UTC+; WIB = 7).
- `min_delay`/`max_delay` = jeda acak antar kirim per nomor (detik). **0 = pakai default server**.
- `rate_max`/`rate_window_min` = batas **X pesan per nomor tiap Y menit** (anti-banned; mis. 15 tiap 30 menit). **0 = pakai default server**.
- Di luar jam kerja, pesan **menunggu** di antrian (tidak hilang).

---

## Contoh integrasi: kirim 700 tagihan

**PHP (ringkas):**
```php
$key  = 'CLIENT_KEY';
$base = 'http://27.112.79.2:3600';

foreach ($tagihan as $t) {
    $post = [
        'to'         => $t['no_wa'],
        'text'       => $t['pesan'],
        'client_ref' => $t['kode'],                          // mis. IU-SD-072026-00039
        'file'       => new CURLFile($t['pdf_path'], 'application/pdf', 'tagihan.pdf'),
    ];
    $ch = curl_init("$base/api/enqueue");
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER     => ["X-API-Key: $key"],
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => $post,                     // multipart otomatis
    ]);
    curl_exec($ch); curl_close($ch);
}
// Semua langsung "queued"; gateway menetes mengirim. Cek hasil berkala:
// POST /api/status { "refs": [ ...semua kode... ] }
```

**Node.js (ringkas):**
```js
import fs from "node:fs";
const base = "http://27.112.79.2:3600", key = "CLIENT_KEY";

for (const t of tagihan) {
  const fd = new FormData();
  fd.append("to", t.noWa);
  fd.append("text", t.pesan);
  fd.append("client_ref", t.kode);
  fd.append("file", new Blob([fs.readFileSync(t.pdfPath)], { type: "application/pdf" }), "tagihan.pdf");
  await fetch(`${base}/api/enqueue`, { method: "POST", headers: { "X-API-Key": key }, body: fd });
}
```

**Polling status (mis. tiap beberapa menit):**
```bash
curl -X POST http://27.112.79.2:3600/api/status \
  -H "X-API-Key: CLIENT_KEY" -H "Content-Type: application/json" \
  -d '{"refs":["IU-SD-072026-00039", "..."]}'
```
Anggap **`delivered`/`read`** = sukses; `failed` bisa di-retry; `invalid` = nomor salah.

---

## Catatan penting

- **Idempotensi:** selalu isi `client_ref` unik. Aman mengirim ulang request yang sama.
- **Ritme:** gateway sudah mengatur jeda & rotasi antar nomor. Aplikasi **tidak perlu**
  memberi jeda sendiri — cukup enqueue semua sekaligus.
- **Kuota:** tiap nomor punya batas harian (diatur di dashboard). Kalau semua nomor
  mencapai batas, sisa antrian menunggu sampai kuota tersedia (tidak hilang).
- **Lampiran** disimpan sementara di server dan dihapus otomatis setelah terkirim.
- **Nomor tujuan** sebaiknya sudah pernah berinteraksi & valid; nomor tak terdaftar
  otomatis `invalid`.
