# Whatsapp API

> Skill untuk integrasi WhatsApp Business API — kirim pesan, notifikasi, tagihan, dan customer service otomatis. TRIGGER ketika: user minta kirim pesan WA otomatis, buat chatbot WhatsApp, integrasi WA Business, kirim invoice via WA, notifikasi order via WhatsApp, atau setup WA API. Juga trigger saat: wa.me, WhatsApp Cloud API, Fonnte, Wablas, atau chat automation.

- Skill: `edorabma9304/whatsapp-api` (Agent Skill)
- Install (CLI): `npx skillmds@latest add edorabma9304/whatsapp-api`
- Raw SKILL.md: https://api.skillmd.com/api/skills/edorabma9304/whatsapp-api/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: edorabma9304 (https://skillmd.com/u/edorabma9304)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/edorabma9304/whatsapp-api

---


# WhatsApp API Integration Skill

Skill untuk integrasi WhatsApp Business API dalam aplikasi — kirim tagihan, notifikasi pesanan, reminder, dan customer service.

---

## Opsi Integrasi

| Provider | Harga | Kelebihan | Kekurangan |
|----------|-------|-----------|------------|
| **wa.me link** | Gratis | Tanpa API, langsung buka WA | Manual, tidak bisa broadcast |
| **WhatsApp Cloud API** (Meta) | Per conversation | Official, gratis 1000 convo/bulan | Setup rumit, perlu Meta Business |
| **Fonnte** | Mulai 30rb/bulan | Mudah, API REST simple, Indonesia | Third-party, risiko banned |
| **Wablas** | Mulai 50rb/bulan | Mudah, support grup | Third-party |

---

## 1. wa.me Link (Tanpa API — Paling Simple)

### Buka Chat Langsung
```javascript
const kirimWA = (nomor, pesan) => {
  // Format nomor: hapus 0 di depan, ganti +62
  const nomorClean = nomor.replace(/^0/, '62').replace(/[^0-9]/g, '')
  const pesanEncoded = encodeURIComponent(pesan)
  window.open(`https://wa.me/${nomorClean}?text=${pesanEncoded}`, '_blank')
}
```

### Template Tagihan
```javascript
const templateTagihan = (pesanan, pengaturan) => {
  const template = pengaturan.templateWA || defaultTemplate
  return template
    .replace('{nama}', pesanan.pelangganNama)
    .replace('{invoice}', pesanan.nomorInvoice)
    .replace('{total}', formatRp(pesanan.total))
    .replace('{sisa}', formatRp(pesanan.total - (pesanan.dp || 0) - (pesanan.pelunasan || 0)))
    .replace('{tanggal}', formatTgl(pesanan.tanggalAmbil))
    .replace('{rekening}', pengaturan.nomorRekening)
}

const defaultTemplate = `Halo {nama},

Pesanan Anda *{invoice}* senilai *{total}*.
Sisa pembayaran: *{sisa}*

Mohon transfer sebelum tanggal {tanggal} ke:
{rekening}

Konfirmasi pembayaran via chat ini.
Terima kasih! 🙏`
```

### Tombol Kirim WA di UI
```jsx
const KirimWAButton = ({ pesanan, pengaturan }) => {
  const pelanggan = getPelanggan(pesanan.pelangganId)
  const handleKirim = () => {
    const pesan = templateTagihan(pesanan, pengaturan)
    kirimWA(pelanggan.kontak, pesan)
  }

  return (
    <button onClick={handleKirim} className="btn bg-green-600 hover:bg-green-700 text-white">
      <MessageCircle size={16} /> Kirim via WA
    </button>
  )
}
```

---

## 2. WhatsApp Cloud API (Official Meta)

### Setup
1. Buat Meta Business Account di business.facebook.com
2. Buat App di developers.facebook.com → tipe "Business"
3. Tambahkan produk "WhatsApp" → dapatkan Phone Number ID & Token
4. Simpan credentials di environment variables

### Kirim Pesan Text
```javascript
const WHATSAPP_TOKEN = process.env.WHATSAPP_TOKEN
const PHONE_NUMBER_ID = process.env.WHATSAPP_PHONE_ID

const kirimPesanWA = async (nomorTujuan, pesan) => {
  const response = await fetch(
    `https://graph.facebook.com/v18.0/${PHONE_NUMBER_ID}/messages`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${WHATSAPP_TOKEN}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        messaging_product: 'whatsapp',
        to: nomorTujuan,  // format: 6281234567890
        type: 'text',
        text: { body: pesan },
      }),
    }
  )
  return response.json()
}
```

### Kirim Template Message (untuk notifikasi)
```javascript
const kirimTemplateWA = async (nomorTujuan, templateName, params) => {
  const response = await fetch(
    `https://graph.facebook.com/v18.0/${PHONE_NUMBER_ID}/messages`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${WHATSAPP_TOKEN}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        messaging_product: 'whatsapp',
        to: nomorTujuan,
        type: 'template',
        template: {
          name: templateName,
          language: { code: 'id' },
          components: [
            {
              type: 'body',
              parameters: params.map(p => ({ type: 'text', text: p })),
            },
          ],
        },
      }),
    }
  )
  return response.json()
}

// Contoh: kirim notifikasi pesanan
kirimTemplateWA('6281234567890', 'order_confirmation', [
  'Ibu Sari',         // {1} nama
  'INV-2024-001',     // {2} invoice
  'Rp285.000',        // {3} total
  '28 Mar 2024',      // {4} tanggal ambil
])
```

### Kirim Document (PDF Invoice)
```javascript
const kirimDocumentWA = async (nomorTujuan, documentUrl, filename, caption) => {
  const response = await fetch(
    `https://graph.facebook.com/v18.0/${PHONE_NUMBER_ID}/messages`,
    {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${WHATSAPP_TOKEN}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        messaging_product: 'whatsapp',
        to: nomorTujuan,
        type: 'document',
        document: {
          link: documentUrl,
          filename: filename,
          caption: caption,
        },
      }),
    }
  )
  return response.json()
}
```

### Webhook — Terima Pesan Masuk
```javascript
// Express endpoint
app.post('/webhook/whatsapp', (req, res) => {
  const { entry } = req.body

  for (const e of entry) {
    for (const change of e.changes) {
      if (change.value.messages) {
        for (const msg of change.value.messages) {
          const from = msg.from           // nomor pengirim
          const text = msg.text?.body      // isi pesan
          const type = msg.type            // text, image, document, dll

          handleIncomingMessage(from, text, type)
        }
      }
    }
  }

  res.sendStatus(200)
})

// Verifikasi webhook
app.get('/webhook/whatsapp', (req, res) => {
  const VERIFY_TOKEN = process.env.WHATSAPP_VERIFY_TOKEN
  if (req.query['hub.verify_token'] === VERIFY_TOKEN) {
    res.send(req.query['hub.challenge'])
  } else {
    res.sendStatus(403)
  }
})
```

---

## 3. Fonnte (Third-party — Indonesia)

### Kirim Pesan
```javascript
const FONNTE_TOKEN = process.env.FONNTE_TOKEN

const kirimViaFonnte = async (nomorTujuan, pesan) => {
  const response = await fetch('https://api.fonnte.com/send', {
    method: 'POST',
    headers: {
      'Authorization': FONNTE_TOKEN,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      target: nomorTujuan,
      message: pesan,
    }),
  })
  return response.json()
}
```

### Kirim dengan File
```javascript
const kirimFileViaFonnte = async (nomorTujuan, pesan, fileUrl) => {
  const response = await fetch('https://api.fonnte.com/send', {
    method: 'POST',
    headers: { 'Authorization': FONNTE_TOKEN },
    body: JSON.stringify({
      target: nomorTujuan,
      message: pesan,
      url: fileUrl,         // URL file (PDF, image)
      filename: 'invoice.pdf',
    }),
  })
  return response.json()
}
```

---

## Template Pesan

### Konfirmasi Pesanan
```
Halo {nama}! 👋

Pesanan Anda sudah kami terima:
📋 No: *{invoice}*
🛒 {items}
💰 Total: *{total}*

Akan siap tanggal *{tanggal}*.
Terima kasih sudah memesan! 🙏
```

### Reminder Pembayaran
```
Halo {nama},

Ini reminder untuk pesanan *{invoice}*:
💰 Total: *{total}*
✅ Terbayar: *{terbayar}*
⏳ Sisa: *{sisa}*

Mohon transfer ke:
🏦 {rekening}

Konfirmasi via chat ini setelah transfer.
Terima kasih! 🙏
```

### Pesanan Siap
```
Halo {nama}! 🎉

Pesanan Anda *{invoice}* sudah *SIAP*!

📍 Pengambilan: {metode}
📅 Tanggal: {tanggal}

{catatan_pengiriman}

Terima kasih! 😊
```

### Pesanan Selesai
```
Halo {nama}! ✨

Pesanan *{invoice}* sudah *SELESAI*.

Terima kasih sudah menjadi pelanggan kami!
Jangan ragu untuk pesan lagi ya 😊

⭐ Puas dengan layanan kami? Ceritakan ke teman-teman ya!
```

---

## Format Nomor Indonesia

```javascript
// Normalisasi nomor WA
const formatNomorWA = (nomor) => {
  let clean = nomor.replace(/[^0-9]/g, '')

  // 08xxx → 628xxx
  if (clean.startsWith('0')) {
    clean = '62' + clean.slice(1)
  }
  // +62xxx → 62xxx (sudah clean dari replace)

  return clean
}

// Validasi nomor WA Indonesia
const isValidWANumber = (nomor) => {
  const clean = formatNomorWA(nomor)
  return /^62[0-9]{9,13}$/.test(clean)
}
```

---

## Aturan

- Jangan spam — kirim pesan hanya untuk transaksi yang relevan
- Hormati jam operasional — jangan kirim di luar jam 08:00-20:00
- Sediakan opt-out — pelanggan harus bisa berhenti terima pesan
- Jangan simpan WhatsApp token di frontend — selalu di backend/env
- Rate limit: WA Cloud API max 80 pesan/detik, Fonnte sesuai plan
- Handle error & retry: network timeout, invalid number, blocked
- Log semua pesan terkirim untuk audit trail

