Lewati ke konten
KonekSip API

Referensi API

Semua endpoint, payload webhook, dan kode error REST API KonekSip.

Base URL

https://koneksip.com/api

Deskripsi OpenAPI 3.1 yang bisa dibaca mesin untuk API ini ada di https://koneksip.com/api/openapi.json. Tidak butuh API key, dan bisa diimpor ke Postman atau Insomnia.

Autentikasi

Semua permintaan API memerlukan autentikasi dengan API key, dikirim lewat header Authorization.

Autentikasi Header

Kirim API key Anda sebagai Bearer token pada setiap permintaan.

Authorization: Bearer YOUR_API_KEY

Catatan: Jaga API key Anda tetap aman dan jangan pernah membagikannya secara publik.

Konvensi

  • Body request dan response berupa JSON. Kirim Content-Type: application/json pada request yang memiliki body.
  • Id pada path ({message_id}, {receiver}, ...) harus di-URL-encode.
  • message_id adalah id pesan di channelnya. Nilainya sama di response kirim, di webhook, dan di path Mark as Read, React, Edit, dan Delete. Formatnya tergantung channel: 3EB0… pada channel Tidak Resmi (QR), wamid.… pada channel Resmi (Cloud API), dan header Message-ID (<…@…>) pada email.
  • Keberhasilan ditentukan oleh status HTTP: 200 berarti permintaan berhasil. Tidak ada field status di body.
  • Body sukses selalu berisi message dan, jika ada hasil, field data. Hanya response yang memakai data, field request bersifat datar.
  • Setiap paket memiliki batas pesan bulanan. Setelah tercapai, endpoint pengiriman mengembalikan 429 quota_exceeded sampai bulan depan atau sampai upgrade.
  • Request yang mengirim pesan atau email dibatasi 60 per menit untuk setiap API key, dan seluruh request digabung 120 per menit. Setiap response membawa X-RateLimit-Limit, X-RateLimit-Remaining, dan X-RateLimit-Reset (detik sampai jendela direset).
  • Pengguna WhatsApp yang memakai username bisa menghubungi Anda tanpa nomor telepon. Meta lalu mengenalinya dengan business-scoped user ID (BSUID, misalnya ID.13491208655302741918). Percakapan seperti itu memakai BSUID sebagai receiver-nya: Anda melihatnya di webhook dan di endpoint baca, dan membalas dengan mengirim BSUID itu sebagai receiver. Ini berlaku di channel Resmi (Cloud API). Receiver berupa nomor telepon tetap berfungsi.
  • Error dijelaskan di Error.
  • Beberapa endpoint hanya berfungsi di channel Tidak Resmi (QR) dan menyebutkannya, channel Resmi mendapat error unsupported_channel di sana.

Idempotensi

Kirim header Idempotency-Key (string unik apa pun, maksimal 255 karakter) pada POST /api/messages dan POST /api/emails. Jika Anda mengulang setelah timeout dengan key dan body yang sama, response sukses pertama dikembalikan lagi, dengan header Idempotent-Replayed: true, dan tidak ada yang terkirim dua kali. Key diingat selama 24 jam. Memakai ulang key dengan body berbeda mengembalikan idempotency_key_reused, pengulangan saat request pertama masih berjalan mengembalikan idempotency_in_progress. Request yang gagal tidak menyimpan key.

Idempotency-Key: 7c9e6679-7425-40de-944b-e07fc1f90ae7

Kirim Teks

Kirim pesan teks ke nomor WhatsApp. Setiap pesan, apa pun jenisnya, dikirim dengan POST /api/messages, field type (text, media, buttons atau template) menentukan jenisnya dan field lain di body bergantung padanya.

POST /api/messages

Body Request

{
  "type": "text",
  "receiver": "string (required) - Phone number with country code (e.g., 628123456789)",
  "message": "string (required) - Message content",
  "reply_to": "string (optional) - message_id of an earlier message to quote",
  "typing": "boolean (optional, default false) - WhatsApp (QR) only. true shows \"typing...\" before sending, so the reply takes up to 3 seconds longer"
}

Contoh Request

POST /api/messages
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "type": "text",
  "receiver": "628123456789",
  "message": "Hello! This is a test message."
}

Response Sukses (200 OK)

{
  "message": "Message sent.",
  "data": { "message_id": "3EB0C767D0B1A2F4E5A9B3" }
}

Response Error

{
  "code": "invalid_receiver",
  "message": "Invalid WhatsApp number."
}

Kirim Media

Kirim gambar, video, dokumen, atau file audio.

POST /api/messages

Body Request

{
  "type": "media",
  "receiver": "string (required) - Phone number with country code (e.g., 628123456789)",
  "url": "string (required) - Media URL",
  "caption": "string (optional)",
  "media_type": "string (required) - image|video|audio|file",
  "voice": "boolean (optional) - Send audio as a voice note",
  "reply_to": "string (optional) - message_id of an earlier message to quote",
  "typing": "boolean (optional, default false) - WhatsApp (QR) only. true shows \"typing...\" before sending, so the reply takes up to 3 seconds longer"
}

Contoh Request

POST /api/messages
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "type": "media",
  "receiver": "628123456789",
  "url": "https://example.com/image.jpg",
  "caption": "Check out this image!",
  "media_type": "image"
}

Jenis Media

  • image: gambar JPG, PNG
  • video: video MP4, 3GP
  • audio: file audio MP3, OGG, AAC
  • file: PDF, DOC, XLS, dan dokumen lainnya

Response Sukses (200 OK)

{
  "message": "Media sent.",
  "data": { "message_id": "3EB0C767D0B1A2F4E5A9B3" }
}

Kirim Button

Kirim pesan dengan hingga 3 tombol interaktif.

Channel Tidak Resmi dan Resmi. Channel Tidak Resmi mendukung hingga 3 tombol dari jenis apa pun. Channel Resmi (Cloud API) mendukung hingga 3 tombol quick_reply, atau satu tombol url, dengan label maksimal 20 karakter, pesan maksimal 1024 karakter, dan footer maksimal 60. Selain itu ditolak dengan validation_failed, dan pesan ke channel Resmi hanya bisa dikirim dalam 24 jam setelah pesan terakhir pelanggan. Jenis channel lain ditolak dengan unsupported_channel. Tombol di channel Tidak Resmi berjalan lewat protokol WhatsApp Web yang tidak resmi, sehingga WhatsApp tidak menjaminnya dan tombol mungkin tidak tampil di semua ponsel atau versi aplikasi.

POST /api/messages

Body Request

{
  "type": "buttons",
  "receiver": "string (required) - Phone number with country code (e.g., 628123456789)",
  "message": "string (required) - Message content",
  "footer": "string (optional) - Small text shown below the message",
  "typing": "boolean (optional, default false) - WhatsApp (QR) only. true shows \"typing...\" before sending, so the reply takes up to 3 seconds longer",
  "buttons": [
    {
      "type": "string (required) - quick_reply|url|call|copy",
      "text": "string (required) - Button label, max 25 characters (20 on Official channels)",
      "value": "string - Required for url, call and copy. Optional for quick_reply"
    }
  ]
}

Jenis Tombol

  • quick_reply: Mengirim tombol kembali kepada Anda sebagai pesan masuk. value adalah ID balasan opsional, jika kosong, label dipakai sebagai ID.
  • url: Membuka tautan. value harus diawali http:// atau https://.
  • call: Menelepon sebuah nomor. value adalah nomor telepon dengan kode negara (mis. +628123456789).
  • copy: Menyalin teks ke clipboard. value adalah teks yang disalin (mis. kode promo atau OTP).

Anda dapat mengirim 1 sampai 3 tombol per pesan.

Contoh Request

POST /api/messages
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "type": "buttons",
  "receiver": "628123456789",
  "message": "Your order #1024 has shipped. What would you like to do?",
  "footer": "KonekSip Store",
  "buttons": [
    { "type": "quick_reply", "text": "Contact support" },
    { "type": "url", "text": "Track order", "value": "https://example.com/track/1024" },
    { "type": "call", "text": "Call us", "value": "+628123456789" }
  ]
}

Response Sukses (200 OK)

{
  "message": "Buttons sent.",
  "data": { "message_id": "3EB0C767D0B1A2F4E5A9B3" }
}

Response Error

{
  "code": "unsupported_channel",
  "message": "This channel does not support this action."
}

Saat pelanggan menekan tombol quick_reply, tombol itu tiba di webhook Anda sebagai event message.received. Label tombol ada di message dan ID balasan ada di button_reply.id.

Kirim List

Kirim pesan dengan menu hingga 10 pilihan. Pelanggan menekan tombol, memilih satu baris, dan pilihannya tiba di webhook Anda.

Hanya channel Resmi (Cloud API). Jenis channel lain ditolak dengan error unsupported_channel. Seperti semua pesan bebas di channel Resmi, list hanya bisa dikirim dalam 24 jam setelah pesan terakhir pelanggan, gunakan template di luar jendela itu.

POST /api/messages

Request Body

{
  "type": "list",
  "receiver": "string (wajib) - Nomor telepon dengan kode negara (mis. 628123456789)",
  "message": "string (wajib) - Isi pesan, maks 1024 karakter",
  "footer": "string (opsional) - Teks kecil di bawah pesan, maks 60 karakter",
  "button_text": "string (wajib) - Label tombol yang membuka daftar, maks 20 karakter",
  "sections": [
    {
      "title": "string - Judul bagian, maks 24 karakter. Wajib jika ada lebih dari satu bagian",
      "rows": [
        {
          "id": "string (wajib) - Nilai yang dikirim ke webhook Anda, maks 200 karakter",
          "title": "string (wajib) - Judul baris, maks 24 karakter",
          "description": "string (opsional) - Deskripsi baris, maks 72 karakter"
        }
      ]
    }
  ]
}

Batas

  • Sebuah list punya 1 sampai 10 bagian dan paling banyak 10 baris secara total.
  • Setiap bagian butuh title jika ada lebih dari satu bagian.
  • Batas panjang judul dan deskripsi berasal dari WhatsApp, request yang melewatinya ditolak dengan validation_failed sebelum ada yang dikirim.

Contoh Request

POST /api/messages
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "type": "list",
  "receiver": "628123456789",
  "message": "Topik apa yang ingin Anda tanyakan?",
  "footer": "KonekSip Support",
  "button_text": "Pilih topik",
  "sections": [
    {
      "title": "Pesanan",
      "rows": [
        { "id": "order_status", "title": "Status pesanan", "description": "Di mana paket saya?" },
        { "id": "order_cancel", "title": "Batalkan pesanan" }
      ]
    },
    {
      "title": "Akun",
      "rows": [{ "id": "account_login", "title": "Gagal login" }]
    }
  ]
}

Respons Sukses (200 OK)

{
  "message": "List sent.",
  "data": { "message_id": "wamid.HBgM..." }
}

Saat pelanggan memilih satu baris, pilihannya tiba di webhook sebagai event message.received. Judul baris ada di message dan id baris ada di button_reply.id.

Kirim Template

Kirim template pesan WhatsApp yang sudah disetujui. Di luar jendela layanan pelanggan 24 jam Meta, ini satu-satunya cara memulai percakapan di channel Resmi.

Hanya channel Resmi. Permintaan untuk channel Tidak Resmi ditolak dengan error wrong_channel_type. Buat dan setujui template di dashboard terlebih dulu.

POST /api/messages

Body Request

{
  "type": "template",
  "receiver": "string (required) - Phone number with country code (e.g., 628123456789)",
  "template_name": "string (required) - Name of the approved template",
  "language_code": "string (required) - e.g., en_US, id",
  "components": "array (optional) - Template parameters in Meta's components format",
  "otp_code": "string (optional) - One-time code for an authentication template, up to 15 characters. Replaces components.",
  "header_format": "string (optional) - IMAGE|VIDEO|DOCUMENT, use together with media",
  "media": "string (optional) - Public URL of the header media"
}

Contoh Request

POST /api/messages
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "type": "template",
  "receiver": "628123456789",
  "template_name": "order_shipped",
  "language_code": "en_US",
  "components": [
    {
      "type": "body",
      "parameters": [
        { "type": "text", "text": "#1024" }
      ]
    }
  ]
}

Contoh Request: kode sekali pakai

POST /api/messages
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "type": "template",
  "receiver": "628123456789",
  "template_name": "login_code",
  "language_code": "id",
  "otp_code": "482913"
}

Untuk template autentikasi, kirim hanya otp_code: KonekSip menaruh kodenya di isi pesan dan di tombol Salin kode, jadi components tidak diperlukan. Kode paling banyak 15 karakter. Kode disimpan disamarkan sebagai ****** di riwayat pesan dan inbox.

Response Sukses (200 OK)

{
  "message": "Template sent.",
  "data": { "message_id": "wamid.HBgM..." }
}

Tandai Chat Sudah Dibaca

Kirim tanda baca (centang biru) untuk pesan terakhir yang dikirim pelanggan di sebuah chat.

POST /api/chats/{receiver}/read-receipts

Contoh Request

POST /api/chats/628123456789/read-receipts
Authorization: Bearer YOUR_API_KEY

Response Sukses (200 OK)

{
  "message": "Chat marked as read."
}

Beri Reaksi

Tambahkan reaksi emoji pada sebuah pesan.

PUT /api/messages/{message_id}/reaction

Body Request

{
  "emoji": "string (required) - One emoji, or an empty string to remove your reaction"
}

Contoh Request

PUT /api/messages/3EB0C767D0B1A2F4E5/reaction
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "emoji": "👍"
}

Response Sukses (200 OK)

{
  "message": "Reaction added."
}

Edit Pesan

Ubah teks pesan yang Anda kirim.

Hanya channel Tidak Resmi. Hanya pesan yang dikirim oleh channel ini yang dapat diedit. {message_id} adalah id pesan di channel Anda, encode untuk dipakai di URL.

PATCH /api/messages/{message_id}

Body Request

{
  "message": "string (required) - The new text"
}

Contoh Request

PATCH /api/messages/3EB0C767D0B1A2F4E5
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

{
  "message": "Hello! This is the corrected text."
}

Response Sukses (200 OK)

{
  "message": "Message edited."
}

Hapus Pesan

Hapus pesan untuk semua orang, atau hanya di sisi Anda.

Hanya channel Tidak Resmi. Menghapus untuk semua orang hanya berfungsi pada pesan yang dikirim oleh channel ini, pesan dari orang lain mengembalikan not_allowed.

DELETE /api/messages/{message_id}

Parameter Query

  • scope - everyone (default) atau me (hapus hanya dari channel ini)
  • delete_media - true untuk ikut menghapus file media yang tersimpan, hanya dengan scope=me

Contoh Request

DELETE /api/messages/3EB0C767D0B1A2F4E5?scope=everyone
Authorization: Bearer YOUR_API_KEY

Response Sukses (200 OK)

{
  "message": "Message deleted for everyone."
}

Daftar Percakapan

Baca percakapan, pesan, kontak, dan template Anda. Daftar dibagi per halaman: kirim limit (1 sampai 100) dan teruskan next_cursor halaman sebelumnya untuk mendapat halaman berikutnya. next_cursor bernilai null di halaman terakhir. Endpoint ini butuh langganan aktif, tetapi channel tidak harus terhubung.

Percakapan channel ini, dari yang paling baru aktif. Obrolan grup ikut disertakan.

GET /api/conversations

Query Parameter

  • status - opsional, open, pending, atau resolved.
  • limit - opsional, 1 sampai 100, bawaan 20.
  • cursor - opsional, next_cursor halaman sebelumnya.

Contoh Request

GET /api/conversations?status=open&limit=20
Authorization: Bearer YOUR_API_KEY

Respons Sukses (200 OK)

{
  "message": "OK",
  "data": [
    {
      "receiver": "628123456789",
      "name": "Dewi Lestari",
      "status": "open",
      "priority": "high",
      "assigned_to": { "id": 3, "name": "Sari Agent" },
      "last_message": {
        "id": "3EB0C767D0B1A2F4E5A9B3",
        "conversation": "628123456789",
        "from_me": false,
        "type": "text",
        "text": "Halo, pesanan saya sudah dikirim?",
        "status": "read",
        "timestamp": 1735689600
      }
    }
  ],
  "next_cursor": "1735689600_4821"
}

receiver adalah nomor telepon atau ID grup . Pakai di endpoint berikutnya. last_message berbentuk sama dengan sebuah pesan.

Daftar Pesan

Pesan dalam satu percakapan, dari yang terbaru.

GET /api/conversations/{receiver}/messages

Query Parameter

  • limit - opsional, 1 sampai 100, bawaan 50.
  • before - opsional, next_cursor halaman sebelumnya, untuk pesan yang lebih lama.

Contoh Request

GET /api/conversations/628123456789/messages?limit=50
Authorization: Bearer YOUR_API_KEY

Respons Sukses (200 OK)

{
  "message": "OK",
  "data": [
    {
      "id": "3EB0C767D0B1A2F4E5A9B3",
      "conversation": "628123456789",
      "from_me": false,
      "type": "text",
      "text": "Halo, pesanan saya sudah dikirim?",
      "status": "read",
      "timestamp": 1735689600
    }
  ],
  "next_cursor": "4790"
}

Percakapan yang tidak ada mengembalikan daftar data kosong.

Ambil Satu Pesan

Satu pesan menurut ID-nya, misalnya message_id yang dikembalikan saat Anda mengirimnya, untuk membaca status pengiriman terbarunya.

GET /api/messages/{id}

Contoh Request

GET /api/messages/3EB0C767D0B1A2F4E5
Authorization: Bearer YOUR_API_KEY

Respons Sukses (200 OK)

{
  "message": "OK",
  "data": {
    "id": "3EB0C767D0B1A2F4E5A9B3",
    "conversation": "628123456789",
    "from_me": false,
    "type": "image",
    "text": "Bukti pembayaran",
    "media": { "url": "https://cdn.example.com/receipt.jpg", "mimetype": "image/jpeg" },
    "status": "read",
    "timestamp": 1735689600
  }
}

Kolom Pesan

  • type - text, image, video, audio, sticker, file, interactive (tombol dan list), template, email, atau other.
  • text - teksnya, keterangan pesan media, nama template, atau isi email.
  • media - hanya pada pesan media: url dan mimetype.
  • email - hanya pada email: subject.
  • status - unread, read, sent, delivered, atau failed, disertai error_reason saat gagal.
  • timestamp - detik epoch Unix.

ID yang tidak dikenal mengembalikan not_found (404).

Daftar Kontak

Pelanggan organisasi Anda, dari yang terlama. Ini daftar pelanggan yang sama dengan yang Anda kelola di menu Pelanggan.

GET /api/contacts

Query Parameter

  • number - opsional, nomor telepon persis, hanya angka.
  • search - opsional, mencocokkan nama, nomor, email, dan perusahaan.
  • limit - opsional, 1 sampai 100, bawaan 50.
  • cursor - opsional, next_cursor halaman sebelumnya.

Contoh Request

GET /api/contacts?number=628123456789
Authorization: Bearer YOUR_API_KEY

Respons Sukses (200 OK)

{
  "message": "OK",
  "data": [
    {
      "id": 12,
      "number": "628123456789",
      "name": "Dewi Lestari",
      "email": "[email protected]",
      "company": "PT Maju",
      "status": "customer",
      "tags": ["vip"],
      "custom_fields": { "order_id": "A-77" },
      "opted_out": false,
      "created_at": 1735600000
    }
  ],
  "next_cursor": null
}

custom_fields adalah kolom tambahan milik pelanggan.

Daftar Template

Template pesan sebuah channel Resmi (Cloud API), untuk dipakai dengan Kirim Template. Hanya template yang disetujui yang dikembalikan kecuali Anda mengirim all=true. Jenis channel lain mengembalikan wrong_channel_type.

GET /api/templates

Contoh Request

GET /api/templates
Authorization: Bearer YOUR_API_KEY

Respons Sukses (200 OK)

{
  "message": "OK",
  "data": [
    { "id": "1234567890", "name": "order_update", "language": "id", "status": "APPROVED", "category": "UTILITY" }
  ]
}

Kolom setiap template persis seperti yang dikembalikan Meta.

Status Channel

Ambil channel pemilik API key, termasuk apakah saat ini sedang terhubung. Gunakan untuk memeriksa channel sebelum mengirim.

GET /api/channel

Response Sukses

{
  "message": "OK",
  "data": {
    "id": "uuid-of-the-channel",
    "name": "My Channel",
    "address": "628123456789",
    "type": "whatsapp_qr",
    "status": "connected",
    "verified": false,
    "verified_name": null
  }
}

status bernilai connected atau disconnected. type bernilai whatsapp_qr (Tidak Resmi, kode QR), whatsapp_cloud (Resmi, Cloud API) , dan address adalah nomor WhatsApp . verified dan verified_name menunjukkan apakah nomor yang terhubung telah mendaftarkan nama tampilan WhatsApp Business, ini bukan lencana terverifikasi ("Green Tick") resmi dari Meta. Keduanya null saat channel terputus.

Webhook

Atur URL webhook untuk menerima pesan WhatsApp masuk secara real-time. Saat seseorang mengirim pesan ke nomor WhatsApp Anda yang terhubung, sistem otomatis mengirim data pesan ke endpoint webhook Anda.

Penting: URL webhook Anda harus dapat diakses publik dan menerima request POST dengan payload JSON. Pengiriman diulang hingga 5 kali dengan backoff jika endpoint Anda tidak terjangkau atau error.

Menyiapkan Webhook

1. Atur URL Webhook

Di pengaturan channel Anda, tambahkan URL webhook:

  • Klik ikon pengaturan pada channel Anda
  • Masukkan URL webhook Anda (mis. https://yourdomain.com/webhook)
  • Simpan pengaturan

Pengiriman

  • Setiap event dikirim sebagai POST dengan body JSON. Jawab dengan status 2xx apa pun, isi response diabaikan.
  • Header pada setiap request: X-Webhook-Id (sama dengan id), X-Webhook-Event (sama dengan type), X-Webhook-Timestamp (sama dengan created_at), dan User-Agent: KonekSip-Webhook/1.0.
  • Pengiriman yang gagal diulang 5 kali lagi, berjarak 1 detik, 5 detik, 30 detik, 2 menit, dan 10 menit, dan setiap percobaan habis waktu setelah 10 detik.
  • id yang sama dikirim lagi pada percobaan ulang, gunakan untuk mengabaikan duplikat.
  • Urutan pengiriman tidak dijamin, event yang diulang bisa tiba setelah event yang lebih baru. Urutkan event berdasarkan created_at.
  • Redirect tidak diikuti, dan URL yang mengarah ke alamat privat atau internal ditolak.

Format Pesan Masuk

Saat pesan diterima, webhook Anda akan menerima request POST dengan data berikut. Setiap event memakai amplop yang sama: id, type, created_at, channel_id, dan data.

POST https://yourdomain.com/webhook type: message.received

Contoh: Pesan Teks

{
  "id": "evt_5b9f6a0e-3c1d-4c0e-9a77-1f2a8d4e6b10",
  "type": "message.received",
  "created_at": 1735689601,
  "channel_id": "uuid-of-the-channel",
  "data": {
    "message_id": "3EB0...",
    "timestamp": 1735689600,
    "from": "628123456789",
    "participant": null,
    "is_group": false,
    "is_me": false,
    "message": "Hello! I need information about your products.",
    "media": null,
    "button_reply": null
  }
}

Contoh: Pesan Media

{
  "id": "evt_8c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
  "type": "message.received",
  "created_at": 1735689601,
  "channel_id": "uuid-of-the-channel",
  "data": {
    "message_id": "3EB0...",
    "timestamp": 1735689600,
    "from": "628123456789",
    "participant": null,
    "is_group": false,
    "is_me": false,
    "message": "caption text, if any",
    "media": {
      "url": "https://.../inbound/.../file.jpg",
      "mimetype": "image/jpeg",
      "type": "image"
    },
    "button_reply": null
  }
}

Contoh: username WhatsApp (BSUID)

{
  "id": "evt_8a7b6c5d-4e3f-4a2b-9c1d-0e9f8a7b6c5d",
  "type": "message.received",
  "created_at": 1735689601,
  "channel_id": "uuid-of-the-channel",
  "data": {
    "message_id": "wamid.HBgM...",
    "timestamp": 1735689600,
    "from": "ID.13491208655302741918",
    "participant": null,
    "is_group": false,
    "is_me": false,
    "message": "Halo, saya memakai username",
    "media": null,
    "button_reply": null,
    "user_id": "ID.13491208655302741918",
    "username": "raka.id"
  }
}

user_id adalah BSUID pelanggan dan username adalah username WhatsApp jika ada, keduanya null di channel lain. from berisi nomor telepon selama Meta membagikannya, dan BSUID jika tidak. Field to pada event message.status mengikuti aturan yang sama.

Contoh: Balasan Tombol

{
  "id": "evt_a1b2c3d4-e5f6-4789-8abc-def012345678",
  "type": "message.received",
  "created_at": 1735689601,
  "channel_id": "uuid-of-the-channel",
  "data": {
    "message_id": "3EB0...",
    "timestamp": 1735689600,
    "from": "628123456789",
    "participant": null,
    "is_group": false,
    "is_me": false,
    "message": "Contact support",
    "media": null,
    "button_reply": {
      "id": "support",
      "text": "Contact support"
    }
  }
}

button_reply bernilai null kecuali pelanggan menekan tombol balasan cepat atau memilih satu baris list. id adalah value yang Anda atur pada tombol (atau label tombol jika dikosongkan) atau id baris, dan text adalah label atau judul barisnya. message juga membawanya.

Di dalam data, message_id mengidentifikasi pesan dan timestamp (detik Unix epoch) adalah waktu pesan dikirim atau diterima. from/to adalah ID WhatsApp biasa (tanpa akhiran @s.whatsapp.net ) , untuk chat grup (is_group: true) from adalah ID grup, bukan nomor telepon, dan participant adalah anggota yang menulis pesan. participant bernilai null di luar grup. media.type bernilai image, video, audio, sticker, atau file.

POST https://yourdomain.com/webhook type: message.status

Dikirim setiap kali pesan yang Anda kirim berubah status pengirimannya (sent, delivered, read, atau failed untuk Cloud API).

{
  "id": "evt_3d2c1b0a-9f8e-4d7c-b6a5-4f3e2d1c0b9a",
  "type": "message.status",
  "created_at": 1735689601,
  "channel_id": "uuid-of-the-channel",
  "data": {
    "message_id": "3EB0...",
    "timestamp": 1735689650,
    "to": "628123456789",
    "status": "delivered"
  }
}

Event Percakapan

Selain pesan, webhook menerima event tentang percakapan itu sendiri. Bentuk amplopnya sama. receiver mengenali percakapan, dengan format yang sama seperti di endpoint percakapan. assigned_by bernilai null saat percakapan ditugaskan otomatis.

POST https://yourdomain.com/webhook type: conversation.assigned

Dikirim saat percakapan ditugaskan, diambil, atau dilepas, oleh anggota tim atau otomatis. assigned_to bernilai null jika sekarang tidak ada yang memegangnya.

{
  "id": "evt_6c5b4a39-2817-4f6e-9d0c-1b2a3f4e5d6c",
  "type": "conversation.assigned",
  "created_at": 1735689601,
  "channel_id": "uuid-of-the-channel",
  "data": {
    "receiver": "628123456789",
    "status": "open",
    "assigned_to": { "id": 3, "name": "Sari Agent" },
    "assigned_by": { "id": 1, "name": "Hel Owner" },
    "department": { "id": 1, "name": "Customer Service" }
  }
}
POST https://yourdomain.com/webhook type: conversation.closed

Dikirim saat anggota tim menandai percakapan sebagai selesai.

{
  "id": "evt_6c5b4a39-2817-4f6e-9d0c-1b2a3f4e5d6c",
  "type": "conversation.closed",
  "created_at": 1735689601,
  "channel_id": "uuid-of-the-channel",
  "data": {
    "receiver": "628123456789",
    "status": "resolved",
    "closed_by": { "id": 3, "name": "Sari Agent" },
    "assigned_to": { "id": 3, "name": "Sari Agent" }
  }
}

Praktik Terbaik

  • Selalu periksa apakah is_me bernilai false sebelum membalas untuk menghindari loop
  • Gunakan HTTPS untuk URL webhook Anda demi keamanan
  • Terapkan timeout dan penanganan error pada webhook Anda
  • Catat pesan masuk untuk debugging dan analitik
  • Pertimbangkan pembatasan laju untuk mencegah spam
  • Validasi struktur data masuk sebelum diproses

Kesalahan

Setiap error berbentuk { "code": "...", "message": "..." } dengan status HTTP yang sesuai. Gunakan code di logika Anda, message ditujukan untuk manusia dan bisa berubah.

HTTP Code Deskripsi
400 invalid_json Body request bukan JSON yang valid
413 payload_too_large Body request terlalu besar
415 unsupported_media_type Body harus dikirim sebagai JSON dengan Content-Type: application/json
400 unsupported_channel Jenis channel ini tidak mendukung aksi tersebut
400 wrong_channel_type Endpoint tidak tersedia untuk jenis channel ini
401 invalid_api_key API key tidak ada atau salah
403 subscription_ended Masa uji coba atau langganan telah berakhir
403 not_allowed Aksi tidak diizinkan pada resource ini
404 not_found Endpoint, pesan, atau chat tidak ada
409 channel_not_connected Channel berhenti atau tidak terhubung
409 idempotency_in_progress Request dengan Idempotency-Key yang sama masih diproses
422 validation_failed Request tidak valid, errors mencantumkan tiap field
422 invalid_receiver Penerima bukan nomor WhatsApp yang valid
422 channel_misconfigured Pengaturan channel belum lengkap
422 verification_failed Kredensial tidak dapat diverifikasi
422 idempotency_key_reused Idempotency-Key sudah dipakai dengan request yang berbeda
429 rate_limited Terlalu banyak request atau kegagalan pengiriman, tunggu retry_after detik (juga dikirim sebagai header Retry-After)
429 quota_exceeded Batas pesan bulanan paket Anda tercapai, pengiriman dilanjutkan bulan depan atau setelah upgrade
500 request_failed Request gagal di sisi kami
502 provider_error WhatsApp atau Meta menolak request, message berisi alasannya

Butuh Bantuan?

Jika Anda punya pertanyaan atau butuh bantuan, tim dukungan kami siap membantu.

Kebijakan Privasi · Syarat Layanan