{"openapi":"3.1.0","info":{"title":"BangunWeb Mail","version":"1.0.0","description":"Kirim email dari domainmu sendiri lewat REST API atau SMTP relay. Semua balasan memakai amplop {ok, data} atau {ok, error, message}. Jalur SMTP: kirim.bangunweb.com port 587 (STARTTLS) atau 465 (TLS), username bebas, password = kunci API yang sama.","contact":{"url":"https://bangunweb.com/kirim-email/docs"}},"servers":[{"url":"https://kirim.bangunweb.com/v1"}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Kunci API berbentuk bwm_live_… dari bangunweb.com/akun/email"}},"parameters":{"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"schema":{"type":"string","maxLength":190},"description":"Nilai unik per permintaan. Permintaan ulang dengan kunci sama membalas rekaman yang pertama (header Idempotent-Replay: true) dan TIDAK mengirim email kedua."}},"schemas":{"Error":{"type":"object","required":["ok","error","message"],"properties":{"ok":{"type":"boolean","enum":[false]},"error":{"type":"string","description":"Slug galat yang stabil; aman dipakai sebagai cabang di kode."},"message":{"type":"string","description":"Kalimat untuk manusia. Bisa berubah; jangan dijadikan patokan kode."}}},"Message":{"type":"object","properties":{"id":{"type":"string","description":"Id pesan; dipakai untuk menelusuri status."},"to_email":{"type":"string"},"from_email":{"type":"string"},"subject":{"type":"string"},"status":{"type":"string","enum":["queued","sent","delivered","deferred","bounced","failed","rejected"]},"error":{"type":["string","null"],"description":"Alasan gagal dalam satu kalimat, bila ada."},"opens":{"type":"integer"},"clicks":{"type":"integer"},"tag":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"},"delivered_at":{"type":["string","null"],"format":"date-time"},"bounced_at":{"type":["string","null"],"format":"date-time"}}},"Domain":{"type":"object","properties":{"id":{"type":"integer"},"domain":{"type":"string"},"status":{"type":"string","enum":["pending","verified","failed"]},"spf":{"type":"boolean"},"dkim":{"type":"boolean"},"dmarc":{"type":"boolean"},"mx":{"type":"boolean","description":"Hanya relevan bila domain ini juga menerima surat."},"records":{"type":"array","description":"Record DNS yang harus dipasang pemilik domain.","items":{"type":"object","properties":{"type":{"type":"string"},"name":{"type":"string"},"value":{"type":"string"},"purpose":{"type":"string","enum":["mx","spf","dkim","dmarc"]},"note":{"type":"string"}}}}}}}},"paths":{"/emails":{"post":{"summary":"Kirim email","description":"Menerima satu penerima atau daftar (maksimal 50). Tiap penerima memotong satu kuota dan mendapat id sendiri.","parameters":[{"$ref":"#/components/parameters/IdempotencyKey"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["from","to"],"properties":{"from":{"type":"string","example":"Toko Bunga <halo@tokobunga.com>"},"to":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"subject":{"type":"string"},"html":{"type":"string"},"text":{"type":"string"},"reply_to":{"type":"string"},"cc":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"bcc":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}]},"headers":{"type":"object","additionalProperties":{"type":"string"}},"attachments":{"type":"array","items":{"type":"object","properties":{"filename":{"type":"string"},"content":{"type":"string","description":"Isi berkas ber-base64."}}}},"tracking":{"type":"boolean","default":true},"tag":{"type":"string"}}}}}},"responses":{"202":{"description":"Diterima dan diserahkan ke antrean pengiriman","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"}}}}}}}},"401":{"description":"Kunci API tidak ada, tidak dikenal, atau sudah dicabut","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Kuota habis, batas harian, atau batas pemanasan IP","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Domain pengirim belum terverifikasi atau bukan milik akun ini","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Idempotency-Key yang sama sedang diproses","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Isi permintaan tidak valid atau penerima sedang ditahan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Melebihi batas laju permintaan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"get":{"summary":"Daftar email terkirim","parameters":[{"name":"status","in":"query","schema":{"type":"string"}},{"name":"to","in":"query","schema":{"type":"string"}},{"name":"tag","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","maximum":100,"default":25}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Daftar pesan","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"total":{"type":"integer"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/Message"}}}}}}}}},"401":{"description":"Kunci API tidak ada, tidak dikenal, atau sudah dicabut","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Melebihi batas laju permintaan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/emails/{id}":{"get":{"summary":"Detail satu email berikut jejak kejadiannya","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Detail pesan","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Message"}}}}}},"401":{"description":"Kunci API tidak ada, tidak dikenal, atau sudah dicabut","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Tidak ditemukan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/quota":{"get":{"summary":"Sisa kuota, batas harian, dan alamat pengirim bersama","responses":{"200":{"description":"Kuota","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"remaining":{"type":"integer"},"used":{"type":"integer"},"daily_limit":{"type":"integer"},"sent_today":{"type":"integer"},"shared_sender":{"type":"string"}}}}}}}},"401":{"description":"Kunci API tidak ada, tidak dikenal, atau sudah dicabut","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/domains":{"get":{"summary":"Daftar domain pengirim","responses":{"200":{"description":"Domain","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"data":{"type":"array","items":{"$ref":"#/components/schemas/Domain"}}}}}}},"401":{"description":"Kunci API tidak ada, tidak dikenal, atau sudah dicabut","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Tambah domain pengirim","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["domain"],"properties":{"domain":{"type":"string"}}}}}},"responses":{"201":{"description":"Domain dibuat; pasang record DNS-nya lalu verifikasi","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Domain"}}}}}},"401":{"description":"Kunci API tidak ada, tidak dikenal, atau sudah dicabut","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Idempotency-Key yang sama sedang diproses","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Isi permintaan tidak valid atau penerima sedang ditahan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/domains/{id}/verify":{"post":{"summary":"Periksa DNS domain lalu tandai terverifikasi bila cocok","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Hasil pemeriksaan","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"data":{"$ref":"#/components/schemas/Domain"}}}}}},"401":{"description":"Kunci API tidak ada, tidak dikenal, atau sudah dicabut","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Tidak ditemukan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/domains/{id}":{"delete":{"summary":"Hapus domain pengirim","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Terhapus","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"data":{"type":"object"}}}}}},"401":{"description":"Kunci API tidak ada, tidak dikenal, atau sudah dicabut","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Tidak ditemukan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/mailboxes":{"get":{"summary":"Kotak surat (email profesional) dan penerusan","responses":{"200":{"description":"Kotak surat & penerusan","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"data":{"type":"object"}}}}}},"401":{"description":"Kunci API tidak ada, tidak dikenal, atau sudah dicabut","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Buat kotak surat baru; balasannya memuat sandi (sekali saja)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["local"],"properties":{"domain":{"type":"string"},"domain_id":{"type":"integer"},"local":{"type":"string","description":"Bagian sebelum @, mis. \"halo\"."},"password":{"type":"string","minLength":8},"quota_mb":{"type":"integer"}}}}}},"responses":{"201":{"description":"Kotak surat dibuat","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"data":{"type":"object","properties":{"id":{"type":"integer"},"address":{"type":"string"},"password":{"type":"string"}}}}}}}},"401":{"description":"Kunci API tidak ada, tidak dikenal, atau sudah dicabut","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Tidak ditemukan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Idempotency-Key yang sama sedang diproses","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Isi permintaan tidak valid atau penerima sedang ditahan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/suppressions":{"get":{"summary":"Alamat yang sedang ditahan","responses":{"200":{"description":"Daftar penahanan","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"data":{"type":"array"}}}}}},"401":{"description":"Kunci API tidak ada, tidak dikenal, atau sudah dicabut","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Tahan sebuah alamat secara manual","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string"},"reason":{"type":"string"}}}}}},"responses":{"201":{"description":"Ditahan","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"data":{"type":"object"}}}}}},"401":{"description":"Kunci API tidak ada, tidak dikenal, atau sudah dicabut","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Isi permintaan tidak valid atau penerima sedang ditahan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/suppressions/{email}":{"delete":{"summary":"Lepas alamat dari daftar penahanan","parameters":[{"name":"email","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Dilepas","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"data":{"type":"object"}}}}}},"401":{"description":"Kunci API tidak ada, tidak dikenal, atau sudah dicabut","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Tidak ditemukan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks":{"get":{"summary":"Daftar webhook","responses":{"200":{"description":"Webhook","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"data":{"type":"array"}}}}}},"401":{"description":"Kunci API tidak ada, tidak dikenal, atau sudah dicabut","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Daftarkan webhook (URL wajib https)","description":"Kejadian yang dikirim: sent, delivered, bounced, opened, clicked, unsubscribed, mailbox_quota_warning. Tiap permintaan membawa X-BWM-Signature = HMAC-SHA256 badan permintaan dengan secret webhook.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url"],"properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"201":{"description":"Webhook dibuat (secret hanya ditampilkan di sini)","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"data":{"type":"object"}}}}}},"401":{"description":"Kunci API tidak ada, tidak dikenal, atau sudah dicabut","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Isi permintaan tidak valid atau penerima sedang ditahan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/webhooks/{id}":{"delete":{"summary":"Hapus webhook","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Terhapus","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"data":{"type":"object"}}}}}},"401":{"description":"Kunci API tidak ada, tidak dikenal, atau sudah dicabut","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Tidak ditemukan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/stats":{"get":{"summary":"Statistik harian","parameters":[{"name":"days","in":"query","schema":{"type":"integer","maximum":90,"default":14}}],"responses":{"200":{"description":"Statistik","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"data":{"type":"object"}}}}}},"401":{"description":"Kunci API tidak ada, tidak dikenal, atau sudah dicabut","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}