> For the complete documentation index, see [llms.txt](https://docs.watzap.id/help/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.watzap.id/help/integrations/watzap-sdk/contoh-use-case.md).

# Contoh Use Case

5 contoh kode siap pakai untuk notifikasi pesanan, OTP login, laporan ke grup, balas otomatis, dan sinkron data pelanggan.

Berikut 5 contoh kebutuhan yang paling sering dikerjakan dengan WatZap SDK. Klik salah satu untuk melihat penjelasan dan kodenya.

Semua contoh menganggap Kamu sudah mengikuti [Instalasi & Kirim Pesan Pertama](/help/integrations/watzap-sdk/instalasi-and-kirim-pesan-pertama.md): SDK sudah terpasang dan API Key ada di file `.env`. Sesuaikan nomor, nama template, dan data lainnya dengan milik Kamu.

<details>

<summary>1. Notifikasi Pesanan &#x26; Cek Status Terkirim (WABA)</summary>

**Cocok untuk:** toko online, marketplace, dan layanan pengiriman.

Kirim kabar ke pelanggan saat pesanan dikirim, lengkap dengan nomor resi. Pelanggan belum tentu chat dalam 24 jam terakhir, jadi gunakan **template** yang sudah disetujui Meta.

**Kirim notifikasi:**

```js
import { WatZap } from '@watzapid/sdk'

const wz = new WatZap()
const pesanan = { noHp: '081234567890', nama: 'Budi', nomorPesanan: 'ORD-001', resi: 'JP1234567890' }

// Template "pesanan_dikirim": "Halo {{1}}, pesanan {{2}} sudah dikirim. No. resi: {{3}}"
const hasil = await wz.whatsapp.messages.sendTemplate({
  to: pesanan.noHp,
  template: 'pesanan_dikirim',
  language: 'id',
  variables: [pesanan.nama, pesanan.nomorPesanan, pesanan.resi], // isi {{1}}, {{2}}, {{3}}
})

// Simpan hasil.id bersama data pesanan untuk mengecek status nanti
console.log('ID pesan:', hasil.id)
```

Parameter `sendTemplate`:

| Parameter   | Wajib | Isi                                                                                                        |
| ----------- | ----- | ---------------------------------------------------------------------------------------------------------- |
| `to`        | Ya    | Nomor tujuan (`08…`, `62…`, atau `+62…`)                                                                   |
| `template`  | Ya    | Nama template, sama persis dengan yang ada di WatZap                                                       |
| `language`  | Tidak | Kode bahasa template, misalnya `id` atau `en_US`. Isi bila ada template bernama sama dengan bahasa berbeda |
| `variables` | Tidak | Isi variabel body. **Array** untuk variabel angka (`{{1}}`, `{{2}}`), **objek** untuk variabel bernama     |
| `header`    | Tidak | Media header `{ url, filename }` untuk template ber-header gambar, video, atau dokumen                     |
| `buttons`   | Tidak | `{ urlSuffix }` untuk tombol URL dinamis, `{ couponCode }` untuk tombol salin kode                         |
| `otpCode`   | Tidak | Kode OTP untuk template kategori Authentication (lihat contoh 2)                                           |

* Contoh variabel bernama: template berisi `{{nama_pelanggan}}` diisi dengan `variables: { nama_pelanggan: 'Budi' }`.
* Template harus sudah ada di WatZap. Kalau tidak ditemukan, muncul error `Template not found`. Cara membuatnya ada di [Cara Membuat Template WABA Official](/help/waba-official/cara-membuat-template-waba-official.md).

**Cek status beberapa saat kemudian:**

```js
import { WatZap } from '@watzapid/sdk'

const wz = new WatZap()
const idPesan = 'wamid.HBgM...' // ID yang disimpan saat mengirim

const cek = await wz.whatsapp.messages.status(idPesan)
console.log(cek.status) // 'sent', 'delivered', 'read', atau 'failed'
if (cek.status === 'failed') console.log('Alasan gagal:', cek.error)
```

Status diperbarui dari laporan Meta: `sent` (terkirim), `delivered` (sampai di HP), `read` (dibaca), atau `failed` (gagal). Pesan yang ditolak Meta setelah dikirim, misalnya karena di luar 24 jam, berubah menjadi `failed` dengan alasan di `cek.error`.

Status pengiriman hanya tersedia untuk pesan WABA yang dikirim lewat API. Pesan Unofficial tidak punya ID pesan maupun status terkirim.

</details>

<details>

<summary>2. Kirim Kode OTP Login (WABA)</summary>

**Cocok untuk:** aplikasi dan website yang perlu memverifikasi nomor HP saat login atau daftar.

```js
import { randomInt } from 'node:crypto'
import { WatZap } from '@watzapid/sdk'

const wz = new WatZap()
const noHp = '081234567890'
const kode = String(randomInt(100000, 1000000)) // 6 digit acak

await wz.whatsapp.messages.sendTemplate({
  to: noHp,
  template: 'kode_login', // template kategori AUTHENTICATION
  language: 'id',
  otpCode: kode,
})
```

* Gunakan template kategori **Authentication**. Cara membuatnya ada di [Membuat Template Authentication atau OTP](/help/menu-marketing/penjelasan-fitur-template/membuat-template-authentication-atau-otp.md).
* Buat kode dengan `randomInt` dari modul `crypto`, bukan `Math.random`, supaya kodenya sulit ditebak.
* Simpan kode OTP di server Kamu, beri batas waktu berlaku, lalu cocokkan saat pengguna memasukkannya.

</details>

<details>

<summary>3. Kirim Laporan Harian ke Grup WhatsApp Tim (Unofficial)</summary>

**Cocok untuk:** sistem internal, gudang, dan tim operasional.

Pesan ke grup hanya bisa dikirim lewat nomor **Unofficial**. Nomor tersebut harus sudah menjadi anggota grupnya.

```js
import { WatZap } from '@watzapid/sdk'

const wz = new WatZap()
const nomor = wz.unofficial.device(process.env.WATZAP_NUMBER_KEY)

// Cari grup berdasarkan namanya
const daftarGrup = await nomor.groups.list()
const grupTim = daftarGrup.find((grup) => grup.name === 'Tim Gudang')
if (!grupTim) throw new Error('Grup "Tim Gudang" tidak ditemukan')

await nomor.groups.sendText({
  groupId: grupTim.id,
  text: 'Laporan hari ini: 25 pesanan dikirim, 3 menunggu pembayaran.',
})
```

* `groups.list()` mengembalikan grup yang diikuti nomor itu. Setiap grup berisi `id` (diakhiri `@g.us`) dan `name`.
* Untuk gambar atau file, gunakan `nomor.groups.sendImage({ groupId, url, caption })` atau `nomor.groups.sendFile({ groupId, url })`.
* Jalankan kode ini secara terjadwal (misalnya dengan cron) supaya laporan terkirim otomatis setiap hari.

</details>

<details>

<summary>4. Balas Otomatis Pesan Masuk (WABA)</summary>

**Cocok untuk:** customer service yang sering menerima pertanyaan yang sama.

**Langkah 1: daftarkan URL webhook.** Cukup dilakukan sekali:

```js
import { WatZap } from '@watzapid/sdk'

const wz = new WatZap()

// Ambil WABA ID dari daftar nomor pengirim
const pengirim = await wz.senders.list()
const waba = pengirim.find((nomor) => nomor.type === 'waba')
if (!waba) throw new Error('Belum ada nomor WABA yang terhubung')

await wz.whatsapp.webhook(waba.wabaId).set('https://tokoku.com/webhook/watzap-x7k29q')
console.log('phoneNumberId nomor WABA Kamu:', waba.phoneNumberId)
```

Satu WABA punya satu URL webhook. Memanggil `set()` lagi akan menimpa URL lama. Catat `phoneNumberId` yang tampil, untuk dipakai di langkah 2.

**Langkah 2: siapkan endpoint untuk menerima pesan.** Contoh ini memakai [Express](https://expressjs.com/) (`npm install express`). Tambahkan `WATZAP_PHONE_NUMBER_ID` ke file `.env` dengan nilai `phoneNumberId` dari langkah 1.

```js
import express from 'express'
import { WatZap, isWabaWebhook } from '@watzapid/sdk'

const wz = new WatZap()
const app = express()
app.use(express.json())

// phoneNumberId nomor WABA Kamu (lihat hasil wz.senders.list())
const PHONE_NUMBER_ID = process.env.WATZAP_PHONE_NUMBER_ID

app.post('/webhook/watzap-x7k29q', async (req, res) => {
  res.sendStatus(200) // jawab secepatnya supaya WatZap tidak menunggu

  const payload = req.body
  if (!isWabaWebhook(payload)) return // contoh ini khusus pesan masuk WABA
  if (payload.phone_number_id !== PHONE_NUMBER_ID) return // bukan untuk nomor Kamu

  const { phone, message_text } = payload.data
  console.log(`Pesan dari ${phone}: ${message_text}`)

  if (message_text?.trim().toLowerCase() === 'jam buka') {
    try {
      // Pelanggan baru saja chat, jadi pesan teks biasa boleh dikirim (masih dalam 24 jam)
      await wz.whatsapp.messages.sendText({ to: phone, text: 'Kami buka setiap hari pukul 08.00-17.00 WIB 😊' })
    } catch (err) {
      console.error('Gagal membalas:', err.name, err.message)
    }
  }
})

app.listen(3000, () => console.log('Webhook siap di port 3000'))
```

Isi penting payload pesan masuk WABA:

| Field                  | Isi                                                                        |
| ---------------------- | -------------------------------------------------------------------------- |
| `phone_number_id`      | ID nomor WABA penerima pesan                                               |
| `data.phone`           | Nomor pengirim pesan (pelanggan)                                           |
| `data.message_type`    | Jenis pesan, misalnya `text`, `image`, atau `button`                       |
| `data.message_text`    | Isi teks. Untuk media tanpa caption berisi penanda seperti `[Image]`       |
| `data.message_payload` | ID tombol atau pilihan yang diklik pelanggan, bila pesannya balasan tombol |

{% hint style="warning" %}
URL webhook harus bisa diakses dari internet. Request webhook dari WatZap **tidak ditandatangani** dan **tidak dikirim ulang** jika gagal. Gunakan URL yang sulit ditebak (seperti contoh di atas), cocokkan `phone_number_id` dengan milik Kamu, pastikan server selalu aktif, dan jangan bagikan URL webhook ke pihak lain.
{% endhint %}

**Untuk nomor Unofficial**, daftarkan webhook dengan `wz.unofficial.device(numberKey).webhook.set(url)`. Bentuk payload-nya berbeda:

* Isi pesan ada di `payload.data.message_body`, dan Number Key penerima di `payload.data.number_key`.
* Webhook Unofficial juga terkirim untuk pesan yang dikirim dari nomor itu sendiri (`payload.data.is_from_me` bernilai `true`). Abaikan pesan tersebut supaya bot tidak membalas dirinya sendiri.

</details>

<details>

<summary>5. Sinkronkan Data Pelanggan ke List</summary>

**Cocok untuk:** CRM, sistem membership, dan toko online yang ingin mengirim broadcast dari dashboard.

Setiap ada pelanggan baru atau data berubah di aplikasi Kamu, simpan juga ke List WatZap.

```js
import { WatZap } from '@watzapid/sdk'

const wz = new WatZap()
const pelanggan = { id: 123, nama: 'Andi', noHp: '081234567890', kota: 'Solo' }

// Sekali saja: lihat ID List yang ada di akun Kamu
const { items } = await wz.lists.list()
console.log(items.map((list) => `${list.listId}  ${list.name}`))

// Setiap ada pelanggan baru atau data berubah
const { subscriber, created } = await wz.lists.subscribers.upsert('LIST_ID', {
  externalId: `pelanggan-${pelanggan.id}`, // ID dari database Kamu, supaya tidak dobel
  phone: pelanggan.noHp,
  name: pelanggan.nama,
  customFields: { kota: pelanggan.kota },
})
console.log(created ? 'Subscriber baru:' : 'Diperbarui:', subscriber.subscriberId)
```

Parameter data subscriber:

| Parameter      | Isi                                                                     |
| -------------- | ----------------------------------------------------------------------- |
| `externalId`   | ID pelanggan dari database Kamu                                         |
| `phone`        | Nomor WhatsApp pelanggan                                                |
| `email`        | Email pelanggan                                                         |
| `name`         | Nama pelanggan                                                          |
| `status`       | `active` atau `inactive`. Bila tidak dikirim, status lama dipertahankan |
| `customFields` | Objek custom field, misalnya `{ kota: 'Solo' }`. Maksimal 100 field     |

* Minimal isi salah satu dari `externalId`, `phone`, atau `email`.
* Data dicocokkan lewat `externalId`, lalu nomor HP, lalu email. Kalau sudah ada, data lama diperbarui sehingga tidak dobel.
* Field yang tidak dikirim tetap dipertahankan.
* Nama custom field baru (seperti `kota`) otomatis ditambahkan ke List.
* Untuk banyak data sekaligus, gunakan `wz.lists.subscribers.bulkUpsert(listId, daftar)`. Maksimal 500 data per panggilan.

**Melihat semua subscriber di List:**

```js
import { WatZap } from '@watzapid/sdk'

const wz = new WatZap()

// Ambil semua subscriber di List, halaman demi halaman secara otomatis
for await (const subscriber of wz.lists.subscribers.list('LIST_ID')) {
  console.log(subscriber.name, subscriber.phone)
}
```

* `for await` mengambil semua data halaman demi halaman secara otomatis, jadi Kamu tidak perlu mengurus nomor halaman.
* Secara bawaan, yang diambil hanya subscriber yang punya nomor HP. Tambahkan `{ channel: 'all' }` sebagai argumen kedua untuk menyertakan subscriber yang hanya punya email.

</details>
