Official Meta Business Partner
WhatsApp API buat kirim Notifikasi Pesanan
Langsung dari aplikasimu. Kalau pelanggan membalas, tim CS lanjut dari inbox WatZap.
Animasi: kode mengirim pesan WhatsApp, pelanggan membaca lalu membalasnya.
// npm install @watzapid/sdk
import { WatZap } from '@watzapid/sdk'
const wz = new WatZap()
const pesan = await wz.whatsapp
.messages.sendText({
to: '081234567890',
text: 'Pesanan #INV-2091 dikirim',
})
npm install @watzapid/sdk
Pelanggan balas notifikasi, tim CS yang lanjutin
Notifikasi dari aplikasimu dan balasan tim CS tercatat di satu percakapan di inbox WatZap.
-
Dikirim aplikasimu lewat API
Pesannya langsung masuk ke percakapan pelanggan itu.
-
Dibalas tim CS dari inbox WatZap
Balasan keluar dari nomor yang sama, jadi pelanggan tetap di satu chat.
Mau sambungkan apa ke aplikasimu?
Konfirmasi pesanan
Begitu order masuk, pelanggan dapat pesan template berisi nomor pesanan dan tombol lacak.
await wz.whatsapp.messages
.sendTemplate({
to: '081234567890',
template: 'order_confirm',
language: 'id',
variables: {
customer_name: 'Budi',
},
})
Kode OTP
Kode login atau verifikasi dikirim lewat template autentikasi WhatsApp.
await wz.whatsapp.messages
.sendTemplate({
to: '081234567890',
template: 'login_otp',
otpCode: '123456',
})
Balasan ke servermu
Setiap pesan masuk diteruskan ke URL webhook-mu sebagai JSON.
// URL-nya didaftarkan lewat
// wz.whatsapp.webhook(wabaId)
// .set(url)
app.post('/watzap/masuk',
(req, res) => {
const body = req.body
if (isWabaWebhook(body)) {
console.log(
body.data.message_text,
)
}
res.sendStatus(200)
})
Sinkron kontak
Daftar pelanggan di databasemu disinkronkan jadi list WatZap. Yang hilang dari daftar ditandai nonaktif, tidak dihapus.
await wz.lists.subscribers.sync(
listId,
pelangganDariDatabase,
{ markMissingInactive: true },
)
Nomor WhatsApp biasa juga bisa dipakai, termasuk kirim ke grup. Lihat caranya
Timeout nggak bikin pesan terkirim dua kali
SDK resmi @watzapid/sdk untuk Node.js 18 ke atas, tanpa dependensi, dengan tipe TypeScript.
import {
WatZap,
WatZapError,
} from '@watzapid/sdk'
const wz = new WatZap()
try {
text: 'Pesanan dikirim',
})
} catch (err) {
// cek status, jangan kirim ulang
}
}
sendTextTidak diulang otomatis kalau koneksi putus di tengah kirim, jadi pelanggan tidak dapat pesan dobel.
'+62 812-3456-7890'Format 08…, 62…, dan +62… dinormalkan sendiri.
WatZapErrorSemua error turunan satu kelas, lengkap dengan kode dan status HTTP.
mayHaveBeenProcessedTrue kalau pesan mungkin sudah sampai. Cek statusnya dulu, jangan langsung kirim ulang.
Pakai ChatGPT, Claude, atau Cursor? Salin prompt berisi daftar method SDK yang benar-benar ada.
Lihat isi prompt
You are helping me integrate WatZap into my app with the official SDK @watzapid/sdk (TypeScript/JavaScript, Node.js 18+). Use only the methods and options listed here. Do not invent others.
SETUP
- Install: npm install @watzapid/sdk
- ESM: import { WatZap } from '@watzapid/sdk' CommonJS: const { WatZap } = require('@watzapid/sdk')
- const wz = new WatZap() // reads the API key from the WATZAP_API_KEY environment variable
- Server-side only. Never put the API key in frontend code or in the repository.
- List methods return a PagedList: `await` it for one page ({ items, page, perPage, total, hasNextPage }), or `for await (const item of ...)` for every item.
WHATSAPP: WABA (official). Sends return Promise<{ id, raw }>; id is the Meta message ID (wamid).
- wz.whatsapp.messages.sendText({ to, text })
- wz.whatsapp.messages.sendTemplate({ to, template, language?, variables?, header?, buttons?, otpCode? })
- variables: an object for NAMED templates, an array for POSITIONAL templates ({{1}}, {{2}})
- header: { url, filename? }; buttons: { urlSuffix?: string | { [buttonIndex]: string }, couponCode?: string }
- wz.whatsapp.messages.sendImage|sendDocument|sendVideo({ to, url, caption? }); sendAudio({ to, url }); react({ to, messageId, emoji })
- wz.whatsapp.messages.sendButtons({ to, body, buttons: [{ id, title }] (1-3, title max 20 bytes), header?, footer? })
- wz.whatsapp.messages.sendList({ to, body, buttonText, sections: [{ title?, rows: [{ id, title, description? }] }] })
- wz.whatsapp.messages.sendLocation({ to, latitude, longitude, name?, address? }); sendContacts({ to, contacts }); sendRaw(payload)
- wz.whatsapp.messages.get(id) / status(id) / list({ status?, phone?, page?, perPage? }) / stats()
- wz.whatsapp.templates.list({ wabaId?, status?, search? }) / get(templateId | { name, wabaId, language? }) / status(ref) / create({ name, category, language, components }) / delete(ref) / sync()
- wz.whatsapp.webhook(wabaId).set(url) / get() / unset()
- Text and media only reach users who messaged the business in the last 24 hours. Otherwise use sendTemplate.
- Do not use wz.whatsapp.broadcasts to send campaigns: the server does not process broadcasts created through the API yet.
WHATSAPP: UNOFFICIAL. numberKey is the 16-character key of a linked number. Sends return { message, senderNumber, raw } with no message ID.
- const device = wz.unofficial.device(numberKey)
- device.messages.sendText({ to, text }) / sendImage({ to, url, caption? }) / sendFile({ to, url })
- device.groups.list() / device.groups.sendText({ groupId, text }) / sendImage({ groupId, url, caption? }) / sendFile({ groupId, url })
- device.validateNumber(phone); device.webhook.set(url) / get() / unset()
- wz.unofficial.conversations.list() / get(id) / messages(id) / markRead(id) / archive(id, archived?)
SHARED
- wz.senders.list() returns every WABA and Unofficial number with its numberKey / wabaId and status
- wz.contacts.list({ listId? }) / get({ contactId } | { phone } | { externalId }) / upsert({ listId, phone?, externalId?, name?, source?, status? }) / delete(contactId) / optIn({ phone }) / optOut({ phone })
- upsert overwrites fields you leave out with empty values: always send every field you want to keep
- opt-out is only recorded: check it yourself before sending
- wz.lists.list() / get(listId) / create({ name, customFields? }) / update(listId, {...}) / delete(listId)
- wz.lists.subscribers.list(listId, { channel? }) / get(listId, id) / upsert(listId, { phone?, email?, externalId?, name?, customFields? }) / delete(listId, id) / bulkUpsert(listId, items) / sync(listId, items, { markMissingInactive? })
- wz.media.uploadUrl({ url }) / list() / get(id) / download(id) / delete(id)
- wz.automations.bots() / rules() / n8nConfig() / n8nLogs() / n8nStats()
PHONE NUMBERS: 08xxx, 62xxx and +62xxx are all accepted and normalized. Use a leading + for non-Indonesian numbers.
ERRORS
- Every error extends WatZapError and has name, message, code, httpStatus, response, mayHaveBeenProcessed; RateLimitError also has retryAfterSeconds.
- Classes: ValidationError (bad input, checked by the SDK or the server), AuthenticationError, PermissionDeniedError, NotFoundError, ConflictError, InsufficientCreditsError, UnprocessableError, RateLimitError, ProviderError, InternalServerError, APIConnectionError, APITimeoutError, APIUserAbortError.
- The SDK already retries whenever it is safe. Do not wrap WhatsApp sends in your own retry loop.
- If err.mayHaveBeenProcessed is true, the message may already have been delivered: check wz.whatsapp.messages.status(id) or log it; do not resend automatically.
Now write the code for this: <DESCRIBE WHAT YOU WANT TO BUILD>
Yang perlu kamu siapkan
Buat akun WatZap
Satu akun untuk dashboard dan API.
Sambungkan nomor WhatsApp Business
Tim tetap bisa membalas dari aplikasi.
Ambil API key dari dashboard
Simpan di server, jangan di kode frontend.
Pasang SDK
Terminal npm install @watzapid/sdk
Tanya Jawab
F.A.Q - Pertanyaan Umum
Yang paling sering ditanyakan soal WhatsApp API
-
Bedanya WhatsApp API resmi dan nomor WhatsApp biasa apa?
WhatsApp API resmi (WABA) memakai nomor yang terdaftar di Meta. Status pesannya bisa dipantau sampai dibaca, dan pesan ke pelanggan yang belum chat dikirim lewat template yang disetujui Meta.
Nomor WhatsApp biasa juga bisa dipakai lewat API, termasuk kirim ke grup, tapi status terkirimnya tidak bisa dilacak.
-
Bisa kirim pesan ke pelanggan yang belum pernah chat?
Bisa, pakai pesan template yang sudah disetujui Meta. Pesan teks dan media biasa hanya sampai ke pelanggan yang chat kamu dalam 24 jam terakhir.
-
Bisa kirim gambar, dokumen, atau tombol?
Bisa. Selain teks, API bisa mengirim gambar, dokumen, video, audio, lokasi, dan kontak, juga pesan bertombol (sampai 3 tombol) dan pesan berisi daftar pilihan.
-
Balasan pelanggan masuk ke mana?
Ke inbox WatZap, tempat tim CS bisa lanjut membalas, dan ke webhook di sistemmu kalau kamu pasang URL-nya. Pesan yang kamu kirim lewat API juga tercatat di percakapan yang sama.
-
Harus pakai Node.js?
Nggak. SDK-nya untuk TypeScript dan JavaScript, tapi bahasa lain bisa langsung memanggil REST API-nya. Caranya ada di dokumentasi API.
-
Nggak bisa koding, tetap bisa pakai WatZap?
Nggak apa-apa. Situsnya WordPress? Pasang plugin resmi WatZap. Toko online juga bisa disambungkan ke WatZap tanpa koding lewat integrasi siap pakai seperti OrderHero, Scalev, dan WooCommerce.
Masih ada yang mau ditanyakan? Chat tim WatZap