Agent Inbox API — Baca dan Kirim Pesan Inbox WhatsApp

Agent Inbox API memberi API key akses ke Inbox WhatsApp. AI Agent atau automation tool dapat membaca percakapan dan mengirim pesan lewat API ini. AI Agent juga dapat mengembalikan percakapan ke tim Anda, berdampingan dengan agent manusia di Inbox yang sama.

Ini adalah API terpisah dari Agent API v2. Tambahkan scope Inbox ke API key workspace mana pun, termasuk key yang sudah punya scope Agent API v2.

Scope

Buat API key di Settings → API Keys, lalu tambahkan salah satu atau kedua scope Inbox. Scope ditetapkan saat key dibuat.

ScopeAkses
inbox.readMembaca percakapan, pesan, dan template yang sudah disetujui.
inbox.writeMengirim pesan, menandai percakapan terbaca, mengubah pemilik atau status, menambah label, dan menambah catatan.

Opsi key

Atur opsi ini pada key, bukan pada tiap request.

  • Daftar koneksi: batasi key ke satu atau beberapa koneksi WhatsApp. Kosongkan agar key berlaku untuk semua koneksi workspace. Setiap route hanya mengembalikan atau menerima percakapan pada koneksi yang diizinkan.
  • Visibilitas nomor: sembunyikan nomor telepon customer pada setiap response. Nomor yang disembunyikan menyisakan 5 digit awal dan 3 digit akhir. Contoh: 628123456789 menjadi 62812****789.

Autentikasi

Kirim key sebagai bearer token pada setiap request.

Authorization: Bearer <api_key_anda>
StatusArti
401Key tidak ada, salah, kedaluwarsa, sudah dicabut, atau tidak punya scope yang dibutuhkan.
403Paket Anda tidak mengizinkan akses ini.
503Inbox belum tersedia untuk workspace ini.

Pemilik percakapan

Setiap percakapan punya satu owner: human, atau agent:<api_key_id> untuk key agent.

  • Percakapan baru mendapat pemilik secara otomatis. Konektor memilih key aktif dengan scope inbox.write paling lama yang mengizinkan koneksi tersebut. Tidak ada key yang cocok membuat pemilik tetap human.
  • Key Anda hanya bisa mengirim pesan pada percakapan yang ia miliki. Mengirim pesan pada percakapan milik human atau agent lain mengembalikan 409 OWNER_MISMATCH.
  • Pesan dari anggota tim selalu mengembalikan percakapan ke human.
  • Key Anda juga bisa meminta pengalihan langsung. Lihat Update percakapan. Key hanya boleh mengatur owner ke human atau ke agent:<api_key_id> miliknya sendiri, tidak pernah ke id agent lain.
  • Setiap perubahan pemilik memicu event webhook inbox.conversation.owner_changed.

Kanal unofficial butuh persetujuan aktif dari salah satu anggota tim sebelum key Anda bisa mengirim pesan di sana. Pengiriman tanpa itu mengembalikan 409 ACKNOWLEDGEMENT_REQUIRED.

Objek percakapan

{
  "id": "7c9ecb52-1f2a-4b3f-9b3e-2b6a2c8f9a11",
  "connection_id": "conn_abc123",
  "channel": "waba",
  "owner": "agent:ak_9f21",
  "status": "open",
  "assigned_to_user_id": null,
  "label_ids": ["vip"],
  "unread_count": 1,
  "window_expires_at": "2026-09-17T14:00:00.000Z",
  "snoozed_until": null,
  "last_message_at": "2026-09-17T09:58:00.000Z",
  "updated_at": "2026-09-17T09:58:01.000Z",
  "contact": { "name": "Budi", "phone": "628123456789" }
}
FieldArti
channelwaba (Cloud API resmi), unofficial (sesi QR), atau partner (nomor dari partner yang terhubung).
ownerhuman atau agent:<api_key_id>. Lihat Pemilik percakapan.
statusopen, pending, snoozed, resolved, atau closed.
window_expires_atWaktu jendela percakapan 24 jam berakhir. null bila sudah berakhir.
contact.phoneDisembunyikan bila key Anda memakai visibilitas nomor tersembunyi.

Objek pesan

{
  "id": "msg_9f2a1b",
  "external_id": "wamid.HBgMNjI4MTIzNDU2Nzg5FQIAERgS",
  "direction": "outbound",
  "kind": "text",
  "text": "Terima kasih, pesanan Anda sedang dikirim.",
  "media": null,
  "status": "sent",
  "error_code": null,
  "actor": { "type": "agent", "id": "ak_9f21" },
  "occurred_at": "2026-09-17T09:58:00.000Z",
  "referral": null
}
FieldArti
directioninbound (dari customer) atau outbound (ke customer).
kindtext, template, image, video, audio, document, location, atau system. Anda hanya bisa mengirim text atau template.
mediaSelalu null. Field kind menunjukkan jenis pesan. Konektor tidak mengirim isi media lewat API ini.
statuspending, sent, delivered, read, atau failed.
actor{ "type": "agent", "id": "<api_key_id>" }, { "type": "user", "id": "<user_id>" }, atau null untuk pesan masuk.
referralDetail iklan click-to-WhatsApp untuk pesan yang membuka percakapan, atau null.
referral.ctwa_clidID klik iklan, atau null.
referral.source_idID iklan atau post, atau null.
referral.source_typeJenis sumber iklan, atau null.
referral.source_urlURL sumber iklan, atau null.
referral.headlineJudul teks iklan, atau null.

Ringkasan route

MethodPathScopeKeterangan
GET/api/v1/inbox/conversationsinbox.readDaftar percakapan
GET/api/v1/inbox/conversations/{id}inbox.readAmbil satu percakapan
GET/api/v1/inbox/conversations/{id}/messagesinbox.readDaftar pesan, dari yang terlama
POST/api/v1/inbox/conversations/{id}/messagesinbox.writeKirim pesan text atau template
POST/api/v1/inbox/conversations/{id}/readinbox.writeTandai percakapan terbaca
PATCH/api/v1/inbox/conversations/{id}inbox.writeUbah pemilik, status, atau label, atau tambah catatan
GET/api/v1/inbox/templatesinbox.readDaftar template yang disetujui

Percakapan di luar daftar koneksi key Anda mengembalikan 404 NOT_FOUND pada setiap route.

Daftar percakapan

GET /api/v1/inbox/conversations

Scope: inbox.read

Query parameterKeterangan
connection_idBatasi hasil ke satu koneksi.
ownerhuman, agent (agent mana pun), atau agent:<api_key_id>.
statusSatu status percakapan.
updated_afterISO date-time. Hanya percakapan yang diupdate setelah waktu ini.
limit1-100. Default 30.
cursorDari response sebelumnya. Kosongkan untuk halaman pertama.
{
  "conversations": [ { "id": "7c9ecb52-...", "...": "..." } ],
  "cursor": "eyJ0IjoxNzU4MDk1..."
}

Panggil route ini lagi dengan cursor diisi nilai yang dikembalikan, untuk membaca halaman berikutnya. Cursor null berarti tidak ada halaman berikutnya.

Ambil satu percakapan

GET /api/v1/inbox/conversations/{id}

Scope: inbox.read. Mengembalikan { "conversation": { ... } }.

Daftar pesan

GET /api/v1/inbox/conversations/{id}/messages

Scope: inbox.read

Query parameterKeterangan
limit1-100. Default 50.
beforeISO date-time. Hanya pesan yang terjadi sebelum waktu ini.
{
  "messages": [ { "id": "msg_1", "...": "..." } ],
  "has_more": false
}

Pesan datang dari yang terlama. Untuk membaca pesan yang lebih lama, panggil lagi dengan before diisi nilai occurred_at dari pesan terlama yang sudah Anda punya.

Kirim pesan

POST /api/v1/inbox/conversations/{id}/messages

Scope: inbox.write. Kirim header Idempotency-Key pada setiap request.

Idempotency-Key: <nilai unik untuk pengiriman ini>

Ulangi request dengan Idempotency-Key yang sama setelah timeout atau error jaringan. Konektor hanya mengirim pesan satu kali. Header yang hilang mengembalikan 400 IDEMPOTENCY_KEY_REQUIRED.

Kirim pesan text saat jendela percakapan 24 jam masih terbuka. Field text menerima maksimal 16.384 karakter:

{
  "kind": "text",
  "text": "Terima kasih, pesanan Anda sedang dikirim.",
  "preview_url": true
}

Kirim template yang sudah disetujui untuk membuka atau memulai ulang percakapan. Kirim maksimal 50 nilai body_params, masing-masing maksimal 2.048 karakter:

{
  "kind": "template",
  "template": {
    "name": "order_confirmation",
    "language": "id",
    "body_params": ["Budi", "INV-2049"]
  }
}

Urutkan body_params sesuai urutan placeholder. Setiap nilai mengisi satu placeholder secara berurutan: {{1}}, {{2}}, dan seterusnya. Lihat Daftar template untuk jumlah placeholder tiap template.

Kedua bentuk request mengembalikan 202 Accepted:

{ "message_id": "msg_9f2a1b", "status": "sent" }

status bernilai sent atau failed. Status pengiriman berikutnya datang lewat webhook inbox.message.status. Idempotency-Key yang sama mengembalikan hasil pertama, termasuk saat hasilnya failed. Pakai key baru untuk mengirim ulang.

kind: "interactive" tidak didukung dan mengembalikan 422 UNSUPPORTED_KIND. Kirim text atau template sebagai gantinya.

Tandai percakapan terbaca

POST /api/v1/inbox/conversations/{id}/read

Scope: inbox.write. Mengembalikan { "id": "7c9ecb52-...", "unread_count": 0 }.

Update percakapan

PATCH /api/v1/inbox/conversations/{id}

Scope: inbox.write. Kirim minimal satu field.

FieldKeterangan
ownerhuman atau agent:<api_key_id> milik Anda sendiri. Id agent lain mengembalikan 403 OWNER_FORBIDDEN.
statusStatus percakapan yang baru.
label_idsMaksimal 20 id label.
note1-4096 karakter. Menambah catatan internal. Catatan tidak terkirim sebagai pesan ke customer.

Ambil alih percakapan:

{ "owner": "agent:ak_9f21" }

Kembalikan ke tim Anda:

{ "owner": "human" }

Mengembalikan { "conversation": { ... } } dengan kondisi terbaru.

Daftar template

GET /api/v1/inbox/templates

Scope: inbox.read. Query parameter opsional: connection_id.

{
  "templates": [
    {
      "id": "tpl_1",
      "connection_id": "conn_abc123",
      "name": "order_confirmation",
      "language": "id",
      "category": "UTILITY",
      "body": "Halo {{1}}, pesanan Anda #{{2}} sudah kami terima.",
      "parameter_count": 2
    }
  ]
}

Hanya template yang sudah disetujui yang muncul. parameter_count adalah jumlah nilai body_params yang dibutuhkan saat mengirim.

Yang Tidak Didukung API Ini

  • Pesan interactive (tombol dan list). Kirim text atau template sebagai gantinya.
  • Parameter header template. Hanya parameter body yang tersedia.
  • Isi media, baik pada pesan maupun payload webhook. Field kind menunjukkan jenisnya.
  • Indikator sedang mengetik. POST .../read hanya menandai percakapan terbaca.

Format Error

Setiap error mengembalikan body JSON dengan field code.

{
  "statusCode": 409,
  "statusMessage": "OWNER_MISMATCH",
  "data": { "code": "OWNER_MISMATCH" }
}

Baca data.code untuk menentukan penanganan error di sisi Anda.

StatusCodeArti
400INVALID_QUERYQuery parameter tidak sesuai tipe atau rentang yang diharapkan.
400INVALID_REQUESTBody request tidak sesuai bentuk yang diharapkan.
400IDEMPOTENCY_KEY_REQUIREDHeader Idempotency-Key tidak ada.
401Key tidak ada, salah, kedaluwarsa, sudah dicabut, atau tidak punya scope yang dibutuhkan.
403Paket Anda tidak mengizinkan akses ini.
403OWNER_FORBIDDENAnda mencoba mengatur owner ke id agent lain.
404NOT_FOUNDPercakapan tidak ada, atau daftar koneksi key Anda tidak mengizinkannya.
409OWNER_MISMATCHKey Anda bukan pemilik percakapan ini.
409CONNECTION_UNAVAILABLEKoneksi WhatsApp belum siap mengirim.
409ACKNOWLEDGEMENT_REQUIREDKanal unofficial butuh persetujuan aktif dari salah satu anggota tim.
409NOT_RETRYABLEPesan ini tidak bisa dicoba ulang.
422UNSUPPORTED_KINDField kind pesan bernilai interactive.
422WINDOW_CLOSEDJendela percakapan 24 jam sudah tertutup. Kirim template sebagai gantinya.
422TEMPLATE_NOT_APPROVEDTidak ada template disetujui yang cocok dengan nama dan bahasa ini.
422INVALID_MESSAGEPesan tidak lolos validasi.
502DELIVERY_FAILEDWhatsApp gagal mengirim pesan ini.
503WHATSAPP_INBOX_UNAVAILABLEInbox belum tersedia untuk workspace ini.

Idempotensi dan Rate Limit

Kirim header Idempotency-Key yang unik pada setiap pengiriman pesan. Pakai nilai yang sama saat mencoba ulang. Konektor hanya mengirim pesan satu kali untuk key yang sama.

Batasnya 300 request per menit. Di atas itu API menjawab 429. Andalkan Idempotency-Key agar percobaan ulang tidak pernah mengirim pesan dua kali.

Event Webhook Inbox

Selain event lead.*, Inbox mengirim empat event lewat webhook yang sama seperti di halaman Webhooks. Header, verifikasi signature, dan pengiriman memakai mekanisme yang sama. Body event membungkus payload:

{ "event": "<nama_event>", "payload": { "...": "..." } }

Ini berbeda dari event lead.*, yang body-nya adalah payload itu sendiri.

inbox.message.received

Terpicu saat pesan dari customer masuk.

{
  "event": "inbox.message.received",
  "payload": {
    "conversation": {
      "id": "7c9ecb52-...",
      "connection_id": "conn_abc123",
      "channel": "waba",
      "owner": "agent:ak_9f21",
      "status": "open",
      "window_expires_at": "2026-09-17T14:00:00.000Z"
    },
    "contact": { "phone": "628123456789", "name": "Budi" },
    "message": {
      "id": "msg_3",
      "external_id": "wamid.HBg...",
      "kind": "text",
      "text": "Pesanan saya sudah dikirim belum?",
      "media": null,
      "occurred_at": "2026-09-17T10:02:00.000Z"
    },
    "referral": null
  }
}

inbox.message.sent

Terpicu untuk setiap pesan keluar, termasuk yang dikirim key Anda sendiri. Bandingkan actor.id dengan id key Anda untuk melewati pesan Anda sendiri.

{
  "event": "inbox.message.sent",
  "payload": {
    "conversation": { "id": "7c9ecb52-...", "connection_id": "conn_abc123", "channel": "waba", "owner": "agent:ak_9f21" },
    "message": { "id": "msg_4", "kind": "text", "text": "Sudah, nomor resi ada di email Anda.", "status": "sent", "occurred_at": "2026-09-17T10:03:00.000Z" },
    "actor": { "type": "agent", "id": "ak_9f21" }
  }
}

inbox.message.status

Terpicu saat status pesan berubah, misalnya menjadi delivered, read, atau failed.

{
  "event": "inbox.message.status",
  "payload": {
    "conversation_id": "7c9ecb52-...",
    "message_id": "msg_4",
    "status": "delivered",
    "error_code": null,
    "at": "2026-09-17T10:03:05.000Z"
  }
}

inbox.conversation.owner_changed

Terpicu saat pemilik percakapan berubah, baik lewat aksi anggota tim maupun PATCH dari key Anda.

{
  "event": "inbox.conversation.owner_changed",
  "payload": {
    "conversation_id": "7c9ecb52-...",
    "owner": "human",
    "actor": { "type": "user", "id": "usr_182" },
    "at": "2026-09-17T10:05:00.000Z"
  }
}

Keamanan

  • Jangan mengirim API key melalui prompt, URL, atau log. Simpan key di secret manager agent Anda.
  • Enkripsi data percakapan atau pesan yang Anda simpan di sisi Anda.
  • Minta scope inbox.read saja bila agent Anda hanya perlu membaca Inbox.

Langkah berikutnya

Butuh Bantuan Lebih Lanjut?

Tim kami siap membantu Anda memaksimalkan tracking iklan dan atribusi bisnis.

© 2026 Konektor. Seluruh hak cipta dilindungi.