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 Pengaturan > Lainnya > API & Webhooks, lalu tambahkan salah satu atau kedua scope Inbox. Scope ditetapkan saat key dibuat.
| Scope | Akses |
|---|---|
inbox.read | Membaca percakapan, pesan, dan template yang sudah disetujui. |
inbox.write | Mengirim pesan, menandai percakapan terbaca, mengubah pemilik atau status, menambah label, dan menambah catatan. |
Opsi key
Atur opsi ini pada key, bukan pada tiap request.
- Nomor WhatsApp yang boleh diakses: 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.
- Sembunyikan nomor pelanggan: sembunyikan nomor telepon customer pada setiap response. Nomor yang disembunyikan menyisakan 5 digit awal dan 3 digit akhir. Contoh:
628123456789menjadi62812****789.
Autentikasi
Kirim key sebagai bearer token pada setiap request.
Authorization: Bearer <api_key_anda>| Status | Arti |
|---|---|
401 | Key tidak ada, salah, kedaluwarsa, sudah dicabut, atau tidak punya scope yang dibutuhkan. |
403 | Paket Anda tidak mengizinkan akses ini. |
503 | Inbox 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.writepaling lama yang mengizinkan koneksi tersebut. Tidak ada key yang cocok membuat pemilik tetaphuman. - Balas otomatis Wulan tidak membalas percakapan milik key Anda. Beri scope
inbox.writehanya pada key yang memang membalas chat. Key yang hanya membaca cukup memakaiinbox.read. - Ingin Wulan membalas lebih dulu, dan agen Anda hanya menangani chat tertentu? Pakai Agent API dengan scope
agent.inbox.write. Scope itu tidak mengambil percakapan baru. Agen mengambil satu percakapan denganowner: "self", lalu menyerahkannya kembali denganowner: "wulan". - Key Anda hanya bisa mengirim pesan pada percakapan yang ia miliki. Mengirim pesan pada percakapan milik
humanatau agent lain mengembalikan409 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
ownerkehuman, keagent:<api_key_id>miliknya sendiri, atau keagent:agentic(Wulan). Id agent lain tidak pernah diizinkan. - Percakapan milik Wulan menampilkan
owner: "agent:agentic". Wulan membalas pesan pelanggan berikutnya. Saat balas otomatis Wulan mati, pengalihan ke Wulan mengembalikan409 AUTO_REPLY_OFF. - 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.
Dua pola integrasi untuk aplikasi Meta lain
Bila Anda juga punya aplikasi WhatsApp Cloud API sendiri pada nomor yang sama dengan koneksi Konektor, pilih salah satu pola berikut.
Pola 1 (disarankan): kirim lewat Konektor
Kirim balasan lewat Kirim pesan. Konektor yang memanggil WhatsApp, jadi pesan langsung tercatat, status delivered/read datang otomatis lewat webhook inbox.message.status, dan pemilik percakapan menjadi key Anda (agent:<api_key_id>).
Alur singkat:
- Terima webhook
inbox.message.received. Simpanconversation.iddanconversation.owner. - Bila
ownersudahhuman, jangan kirim balasan otomatis. Ambil alih dulu lewat Update percakapan bila kebijakan Anda mengizinkan. - Kirim balasan lewat
POST /api/v1/inbox/conversations/{id}/messagesdengan headerIdempotency-Key. - Bila anggota tim menekan "Ambil alih", webhook
inbox.conversation.owner_changeddatang denganowner: "human". Hentikan balasan otomatis pada percakapan itu.
Pesan yang terkirim lewat pola ini tampil di Inbox dengan caption "Oleh AI".
Pola 2: kirim lewat aplikasi Meta Anda sendiri
Untuk masa transisi, bila Anda masih mengirim lewat aplikasi WhatsApp Cloud API sendiri, catat salinannya lewat Catat pesan yang aplikasi lain kirim. Inbox lalu tetap menampilkan percakapan lengkap.
Batasan pola ini: percakapan tetap owner: human, status delivered/read tidak masuk, dan percakapan baru dari catatan ini belum punya nama kontak sampai pesan berikutnya datang lewat Konektor. Bila Anda hanya punya nomor pelanggan, misalnya saat baru memulai integrasi, cari percakapannya lebih dulu lewat parameter phone pada Daftar percakapan.
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" }
}| Field | Arti |
|---|---|
channel | waba (Cloud API resmi), unofficial (sesi QR), atau partner (nomor dari partner yang terhubung). |
owner | human atau agent:<api_key_id>. Lihat Pemilik percakapan. |
status | open, pending, snoozed, resolved, atau closed. |
window_expires_at | Waktu jendela percakapan 24 jam berakhir. null bila sudah berakhir. |
contact.phone | Disembunyikan 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
}| Field | Arti |
|---|---|
direction | inbound (dari customer) atau outbound (ke customer). |
kind | text, template, image, video, audio, document, location, atau system. Anda hanya bisa mengirim text atau template. |
media | Selalu null. Field kind menunjukkan jenis pesan. Konektor tidak mengirim isi media lewat API ini. |
status | pending, sent, delivered, read, atau failed. |
actor | { "type": "agent", "id": "<api_key_id>" }, { "type": "user", "id": "<user_id>" }, atau null untuk pesan masuk. |
referral | Detail iklan click-to-WhatsApp untuk pesan yang membuka percakapan, atau null. |
referral.ctwa_clid | ID klik iklan, atau null. |
referral.source_id | ID iklan atau post, atau null. |
referral.source_type | Jenis sumber iklan, atau null. |
referral.source_url | URL sumber iklan, atau null. |
referral.headline | Judul teks iklan, atau null. |
Ringkasan route
| Method | Path | Scope | Keterangan |
|---|---|---|---|
GET | /api/v1/inbox/conversations | inbox.read | Daftar percakapan |
GET | /api/v1/inbox/conversations/{id} | inbox.read | Ambil satu percakapan |
GET | /api/v1/inbox/conversations/{id}/messages | inbox.read | Daftar pesan, dari yang terlama |
POST | /api/v1/inbox/conversations/{id}/messages | inbox.write | Kirim pesan text atau template |
POST | /api/v1/inbox/conversations/{id}/read | inbox.write | Tandai percakapan terbaca |
PATCH | /api/v1/inbox/conversations/{id} | inbox.write | Ubah pemilik, status, atau label, atau tambah catatan |
POST | /api/v1/inbox/echoes | inbox.write | Catat pesan yang aplikasi lain kirim dari nomor Anda |
GET | /api/v1/inbox/templates | inbox.read | Daftar template yang disetujui |
Percakapan di luar daftar koneksi key Anda mengembalikan 404 NOT_FOUND pada setiap route.
Daftar percakapan
GET /api/v1/inbox/conversationsScope: inbox.read
| Query parameter | Keterangan |
|---|---|
connection_id | Batasi hasil ke satu koneksi. |
phone | Nomor pelanggan, hanya digit, 8-20 digit. Mengembalikan percakapan yang nomornya cocok persis, atau daftar kosong bila tidak ada. Nomor tidak valid mengembalikan 400 INVALID_QUERY. |
owner | human, agent (agent mana pun), atau agent:<api_key_id>. |
status | Satu status percakapan. |
updated_after | ISO date-time. Hanya percakapan yang diupdate setelah waktu ini. |
limit | 1-100. Default 30. |
cursor | Dari 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}/messagesScope: inbox.read
| Query parameter | Keterangan |
|---|---|
limit | 1-100. Default 50. |
before | ISO 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}/messagesScope: 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. Periksa error_code pada pesan yang tersimpan sebelum mengirim lagi.
Jika nilainya delivery_uncertain, periksa percakapan provider sebelum membuat pesan atau key baru. Jangan retry otomatis.
Pakai key baru hanya setelah kegagalan pasti, atau setelah memastikan pesan yang belum pasti itu tidak terkirim.
kind: "interactive" tidak didukung dan mengembalikan 422 UNSUPPORTED_KIND. Kirim text atau template sebagai gantinya.
Catat pesan yang aplikasi lain kirim
POST /api/v1/inbox/echoesScope: inbox.write. Pakai route ini saat aplikasi WhatsApp Cloud API Anda sendiri mengirim pesan dari nomor yang sama. Inbox lalu menampilkan pesan itu di percakapan, dan percakapan tidak lagi terhitung belum dibalas.
{
"connection_id": "conn_abc123",
"to": "628123456789",
"external_id": "wamid.HBgLNjI4MTIzNDU2Nzg5FQIAERgSN0Y3RkIxQ0ZBRkQ5QzY3RkU3AA==",
"kind": "text",
"body": "Terima kasih, invoice Anda sudah siap.",
"occurred_at": "2026-09-18T10:03:00.000Z"
}| Field | Keterangan |
|---|---|
connection_id | Koneksi waba milik workspace Anda. Daftar koneksi pada key harus mengizinkannya. |
to | Opsional. Nomor pelanggan, hanya digit, dengan kode negara (8-20 digit). |
to_user_id | Opsional. BSUID lengkap pelanggan, misalnya US.13491208655302741918. Pola: dua huruf besar, titik, ENT. (opsional), lalu 1-128 huruf atau angka. |
external_id | wamid yang Meta kembalikan ke aplikasi Anda. Satu external_id menyimpan satu pesan. |
kind | text, template, atau interactive. Inbox menyimpan interactive sebagai text. |
body | Teks pesan, atau ringkasan singkat untuk template atau formulir. Maksimal 16.384 karakter. |
occurred_at | Opsional, waktu ISO 8601 dengan offset. Default: sekarang. |
Kirim minimal satu dari to atau to_user_id. Pakai to bila nomor pelanggan diketahui, dan to_user_id bila tidak. Konektor menyambungkan keduanya ke satu percakapan dari data WhatsApp. Field yang tidak dikenal ditolak.
Pelanggan yang memakai username WhatsApp mungkin hanya punya BSUID. Contoh body dengan BSUID saja:
{
"connection_id": "conn_abc123",
"to_user_id": "US.13491208655302741918",
"external_id": "wamid.HBgLMTM0OTEyMDg2NTUFAgASGBQzQTdFMUIyQzRENUY2QTdCOEM5RDAA",
"kind": "text",
"body": "Terima kasih, invoice Anda sudah siap."
}Pesan baru mengembalikan 202 Accepted dengan { "message_id": "msg_9f2a1b", "inserted": true }. external_id yang sama mengembalikan 200 OK dengan inserted: false. Pesan ini sampai ke webhook Anda sebagai inbox.message.sent dengan actor: null. Rule agen Konektor tidak berjalan pada pesan ini.
Tandai percakapan terbaca
POST /api/v1/inbox/conversations/{id}/readScope: inbox.write. Mengembalikan { "id": "7c9ecb52-...", "unread_count": 0 }.
Update percakapan
PATCH /api/v1/inbox/conversations/{id}Scope: inbox.write. Kirim minimal satu field.
| Field | Keterangan |
|---|---|
owner | human, agent:<api_key_id> milik Anda sendiri, atau agent:agentic untuk menyerahkan percakapan ke Wulan. Id agent lain mengembalikan 403 OWNER_FORBIDDEN. Wulan membalas pesan pelanggan berikutnya. Saat balas otomatis Wulan mati, jawabannya 409 AUTO_REPLY_OFF. |
status | Status percakapan yang baru. |
label_ids | Maksimal 20 id label. |
note | 1-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" }Serahkan ke Wulan:
{ "owner": "agent:agentic" }Mengembalikan { "conversation": { ... } } dengan kondisi terbaru.
Daftar template
GET /api/v1/inbox/templatesScope: 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
textatautemplatesebagai gantinya. - Parameter header template. Hanya parameter body yang tersedia.
- Isi media, baik pada pesan maupun payload webhook. Field
kindmenunjukkan jenisnya. - Indikator sedang mengetik.
POST .../readhanya 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.
| Status | Code | Arti |
|---|---|---|
| 400 | INVALID_QUERY | Query parameter tidak sesuai tipe atau rentang yang diharapkan. |
| 400 | INVALID_REQUEST | Body request tidak sesuai bentuk yang diharapkan. |
| 400 | IDEMPOTENCY_KEY_REQUIRED | Header Idempotency-Key tidak ada. |
| 401 | — | Key tidak ada, salah, kedaluwarsa, sudah dicabut, atau tidak punya scope yang dibutuhkan. |
| 403 | — | Paket Anda tidak mengizinkan akses ini. |
| 403 | OWNER_FORBIDDEN | Anda mencoba mengatur owner ke id agent lain. |
| 404 | NOT_FOUND | Percakapan tidak ada, atau daftar koneksi key Anda tidak mengizinkannya. |
| 409 | OWNER_MISMATCH | Key Anda bukan pemilik percakapan ini. |
| 409 | AUTO_REPLY_OFF | Anda menyerahkan percakapan ke Wulan, tetapi balas otomatis Wulan mati. Tidak ada yang berubah. |
| 409 | CONNECTION_UNAVAILABLE | Koneksi WhatsApp belum siap mengirim. |
| 409 | ACKNOWLEDGEMENT_REQUIRED | Kanal unofficial butuh persetujuan aktif dari salah satu anggota tim. |
| 409 | NOT_RETRYABLE | Pesan ini tidak bisa dicoba ulang. |
| 409 | DELIVERY_UNCERTAIN | Hasil pengiriman belum pasti. Periksa percakapan provider sebelum membuat pesan baru; jangan retry otomatis. |
| 422 | UNSUPPORTED_KIND | Field kind pesan bernilai interactive. |
| 422 | WINDOW_CLOSED | Jendela percakapan 24 jam sudah tertutup. Kirim template sebagai gantinya. |
| 422 | TEMPLATE_NOT_APPROVED | Tidak ada template disetujui yang cocok dengan nama dan bahasa ini. |
| 422 | INVALID_MESSAGE | Pesan tidak lolos validasi. |
| 502 | DELIVERY_FAILED | WhatsApp gagal mengirim pesan ini. |
| 503 | WHATSAPP_INBOX_UNAVAILABLE | Inbox 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 enam 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"
}
}inbox.conversation.handover
Terpicu saat asisten Agentic menyerahkan percakapan ke tim Anda. Payload hanya berisi pengenal dan kode alasan.
{
"event": "inbox.conversation.handover",
"payload": {
"conversation_id": "7c9ecb52-...",
"reason": "customer_request",
"assigned_to_user_id": "usr_182",
"occurred_at": "2026-10-11T10:05:00.000Z"
}
}reason berisi salah satu dari keyword, max_replies, customer_request, sensitive_topic, upset, no_answer, atau other. assigned_to_user_id bernilai null jika tidak ada anggota tim yang menerima percakapan.
inbox.conversation.updated
Terpicu saat percakapan berubah: status, label, atau penanggung jawab baru, snooze yang berakhir, atau balasan yang dikirim dari ponsel. Webhook hanya menerimanya jika event ini dipilih pada webhook tersebut. Payload hanya berisi pengenal, status, dan ID label. Tidak ada isi pesan, nomor telepon, atau nama.
{
"event": "inbox.conversation.updated",
"payload": {
"conversation_id": "7c9ecb52-...",
"status": "resolved",
"assigned_to_user_id": "usr_182",
"label_ids": ["lbl_3", "lbl_7"],
"occurred_at": "2026-10-11T10:07:00.000Z"
}
}Satu perubahan dapat mengirim lebih dari satu event, dan retry dapat mengirim event yang sama lagi. Anggap status dan label_ids sebagai keadaan saat pengiriman, dan abaikan event yang sudah Anda proses.
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.readsaja bila agent Anda hanya perlu membaca Inbox.
Langkah berikutnya
Butuh Bantuan Lebih Lanjut?
Tim kami siap membantu Anda memaksimalkan tracking iklan dan atribusi bisnis.
Wulan bantu jawab dan kirim video panduan. Jadwal sesi tersedia lewat Wulan bila masih perlu.
© 2026 Konektor. Seluruh hak cipta dilindungi.