> 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/pakai-sdk-dengan-bantuan-ai.md).

# Pakai SDK dengan Bantuan AI

Salin prompt siap pakai ke ChatGPT, Claude, Cursor, atau GitHub Copilot supaya AI menulis kode WatZap SDK dengan nama fungsi yang benar.

Kalau Kamu belum terbiasa coding, AI assistant seperti ChatGPT, Claude, Cursor, atau GitHub Copilot bisa membantu menuliskan kode integrasi. Masalahnya, AI sering "mengarang" nama fungsi yang sebenarnya tidak ada.

Prompt di bawah ini berisi daftar fungsi WatZap SDK versi **0.2.0** beserta aturan pentingnya. Dengan prompt ini, AI punya acuan yang benar sehingga lebih kecil kemungkinannya mengarang fungsi. Hasilnya tetap perlu Kamu jalankan dan uji sendiri.

## Cara pakai

1. Salin seluruh prompt di bawah (klik ikon salin di pojok kanan atas kotak kode).
2. Tempel ke AI assistant pilihan Kamu.
3. Ganti bagian `<JELASKAN APA YANG INGIN KAMU BUAT>` di baris terakhir dengan kebutuhan Kamu. Boleh ditulis dalam Bahasa Indonesia. Semakin jelas, semakin bagus hasilnya.

Contoh isian baris terakhir:

> Setiap ada pesanan baru di website saya, kirim template WABA `pesanan_baru` ke nomor pembeli berisi nama dan nomor pesanan. Backend saya memakai Express.

{% hint style="warning" %}
Jangan tempel API Key atau Number Key asli ke chat AI. Biarkan kode membacanya dari file `.env`, lalu uji hasilnya dengan nomor HP sendiri sebelum dipakai untuk pelanggan.
{% endhint %}

## Prompt

{% code overflow="wrap" %}

```
You are helping me integrate WatZap into my app with the official SDK @watzapid/sdk version 0.2.0 (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') (in CommonJS, put await inside an async function)
- const wz = new WatZap()  // reads the API key from the WATZAP_API_KEY environment variable. Options: { apiKey?, timeout? (ms, default 60000), maxRetries? (default 2) }
- Every method also accepts per-call options as its last argument: { timeout?, maxRetries?, signal? }
- Server-side only. Never put the API key in frontend code or in the repository. Use the account owner's API key.
- 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). Messages go out from the WABA number connected to the account; the sender cannot be chosen.
- 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 }
  - otpCode: the code for AUTHENTICATION (OTP) templates
- 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? }] }], header?, footer? })
- wz.whatsapp.messages.sendLocation({ to, latitude, longitude, name?, address? }); sendContacts({ to, contacts }); sendRaw(payload)
- wz.whatsapp.messages.get(id) / status(id) / list({ status?, phone?, apiName?, page?, perPage? }) / stats()
  - status(id) returns { id, status: 'sent' | 'delivered' | 'read' | 'failed', error, statusHistory, updatedAt }
- wz.whatsapp.templates.list({ wabaId?, status?, category?, language?, search? }) / get(templateId | { name, wabaId, language? }) / status(ref) / create({ name, category, language, components, wabaId? }) / delete(ref) / sync({ wabaId? })
- wz.whatsapp.webhook(wabaId).set(url) / get() / unset()
- Text, media and interactive messages only reach users who messaged the business in the last 24 hours. Outside that window the send still returns an id, but the status later becomes 'failed'. Use sendTemplate instead.
- 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 number in the API tab. Sends return { message, senderNumber, raw } with no message ID and no delivery status.
- const device = wz.unofficial.device(numberKey)
- device.messages.sendText({ to, text }) / sendImage({ to, url, caption? }) / sendFile({ to, url })
- device.groups.list() returns [{ id, name, participants }] / 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?)

INCOMING WEBHOOKS (POST JSON to the URL set with webhook.set)
- import { isWabaWebhook } from '@watzapid/sdk'; isWabaWebhook(payload) is true for WABA payloads.
- WABA payload: payload.phone_number_id, payload.data.phone (sender), payload.data.message_type, payload.data.message_text, payload.data.message_payload (button id).
- Unofficial payload: payload.type === 'incoming_chat', payload.data.number_key, payload.data.message_body, payload.data.is_from_me (ignore messages where it is true).
- Requests are not signed and not retried. Reply 200 quickly, use a hard-to-guess URL, and check phone_number_id or number_key against my own.

SHARED
- wz.senders.list() returns every WABA ({ type: 'waba', wabaId, phoneNumberId, phone, status }) and Unofficial ({ type: 'unofficial', numberKey, phone, status }) number
- wz.contacts.list({ listId?, status? }) / get({ contactId } | { phone } | { externalId }) / upsert({ listId, phone?, externalId?, name?, source?, status? }) / delete(contactId) / optIn({ phone, reason?, source? }) / optOut({ phone, reason?, source? })
  - 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, { status?, search?, channel? }) / get(listId, id) / upsert(listId, { phone?, email?, externalId?, name?, status?, customFields? }) / delete(listId, id) / bulkUpsert(listId, items) / sync(listId, items, { markMissingInactive? })
  - subscribers.upsert keeps fields you leave out; bulkUpsert and sync take at most 500 items per call
  - subscribers.list returns only subscribers with a phone number unless channel is 'all' or 'email'
- 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, endpoint, response, mayHaveBeenProcessed; RateLimitError also has retryAfterSeconds.
- Classes: ValidationError (bad input, checked by the SDK or the server), AuthenticationError, PermissionDeniedError, NotFoundError, ConflictError, UnprocessableError, RateLimitError, ProviderError, InternalServerError, APIConnectionError, APITimeoutError, APIUserAbortError.
- Check the error type with instanceof, not with httpStatus: some errors arrive with HTTP 200.
- 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.list({ phone }) for WABA, or log it; do not resend automatically.

Now write the code for this, and explain it in Bahasa Indonesia: <JELASKAN APA YANG INGIN KAMU BUAT>
```

{% endcode %}

## Setelah AI memberi kode

1. Simpan API Key (dan Number Key bila perlu) di file `.env`, seperti di [Instalasi & Kirim Pesan Pertama](/help/integrations/watzap-sdk/instalasi-and-kirim-pesan-pertama.md).
2. Jalankan kode itu dan kirim ke nomor HP Kamu sendiri dulu.
3. Kalau muncul error, salin pesan error-nya kembali ke AI, atau cocokkan dengan tabel di [Menangani Error](/help/integrations/watzap-sdk/menangani-error.md).
4. Sebelum dipakai untuk pelanggan, cek lagi poin-poin di [Tips Sebelum Go-Live](/help/integrations/watzap-sdk/tips-sebelum-go-live.md).

## Masalah umum

<details>

<summary>AI memakai fungsi yang tidak ada di prompt</summary>

Balas ke AI: "Gunakan hanya fungsi yang ada di daftar prompt." Kalau masih terjadi, mulai percakapan baru dan tempel ulang prompt di atas secara utuh.

</details>

<details>

<summary>AI meminta API Key asli</summary>

Jangan berikan. Kode yang benar membaca API Key dari `WATZAP_API_KEY` di file `.env`, jadi AI tidak perlu tahu isinya.

</details>
