Dokumentasi Teknis
Postivo API & SMTP Relay
Kirim email transaksional lewat satu endpoint REST atau satu login SMTP. Halaman ini mencakup semua yang dibutuhkan developer — dari domain pertama sampai webhook di produksi.
Mulai Cepat
Kirim email pertama dalam 5 menit.
REST API
Endpoint kirim, batch, lampiran, idempotency.
SMTP Relay
Host, port, dan kode balasan.
Webhook
Event bertanda tangan HMAC.
Domain & DNS
SPF, DKIM, DMARC, Return-Path.
Paket & Penagihan
Kuota, harga, checkout Xendit.
Pengenalan
Postivo adalah layanan email transaksional: OTP, reset password, invoice, notifikasi. Anda mengirim lewat REST API atau SMTP; Postivo memvalidasi, mengantrekan, menandatangani DKIM, mengirim lewat relay, lalu melaporkan setiap perubahan status.
REST / SMTP → validasi (domain, kuota, suppression) → antrean → tanda tangan DKIM → relay (Stalwart; fallback Brevo bila gangguan sementara) → event: queued · sent · delivered · bounced · complained
- Satu pintu masuk. REST dan SMTP memakai aturan validasi yang sama, sehingga hasilnya konsisten.
- Satu email, banyak penerima. Setiap penerima punya status sendiri (
dispatch) dan timeline sendiri. - Aman bagi OTP. Open/click tracking mati secara bawaan agar link verifikasi tidak ditulis ulang.
Base URL
https://api.postivo.my.id/v1 · SMTP: smtp.postivo.my.id · Console: https://postivo.my.id/consoleQuickstart 5 menit
- Buat akun dan verifikasi email Anda.
- Buka Domains → tambahkan domain pengirim (disarankan subdomain, mis.
mail.contoh.com). - Pasang lima record DNS di penyedia DNS Anda, lalu klik Verifikasi sampai status Active.
- Buka API Keys → buat key
livedengan scopeemails:send. Salin — hanya tampil sekali. - Kirim email pertama:
curl https://api.postivo.my.id/v1/emails \
-H "Authorization: Bearer $POSTIVO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "Acme <[email protected]>",
"to": ["[email protected]"],
"subject": "Kode verifikasi Anda",
"html": "<p>Kode: <b>123456</b></p>",
"text": "Kode: 123456"
}'
const res = await fetch('https://api.postivo.my.id/v1/emails', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.POSTIVO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
from: 'Acme <[email protected]>',
to: ['[email protected]'],
subject: 'Kode verifikasi Anda',
html: '<p>Kode: <b>123456</b></p>',
text: 'Kode: 123456',
}),
});
console.log(res.status, await res.json()); // 202
$res = Http::withToken(env('POSTIVO_API_KEY'))
->post('https://api.postivo.my.id/v1/emails', [
'from' => 'Acme <[email protected]>',
'to' => ['[email protected]'],
'subject' => 'Kode verifikasi Anda',
'html' => '<p>Kode: <b>123456</b></p>',
'text' => 'Kode: 123456',
]);
$res->status(); // 202
import os, requests
r = requests.post(
"https://api.postivo.my.id/v1/emails",
headers={"Authorization": f"Bearer {os.environ['POSTIVO_API_KEY']}"},
json={
"from": "Acme <[email protected]>",
"to": ["[email protected]"],
"subject": "Kode verifikasi Anda",
"html": "<p>Kode: <b>123456</b></p>",
"text": "Kode: 123456",
},
)
print(r.status_code, r.json()) # 202
Respons 202 Accepted berarti email sudah divalidasi dan masuk antrean — bukan berarti sudah terkirim. Pantau statusnya di Emails atau lewat webhook.
{
"id": "0192f3a0-7c1e-7b3a-9d4e-5a1f0c2b8e11",
"status": "queued",
"created_at": "2026-10-27T08:15:30Z",
"recipients": [
{ "email": "[email protected]", "dispatch_id": "0192f3a0-7c20-7d11-8a2b-1c3d4e5f6a7b", "status": "QUEUED" }
]
}
Coba tanpa risiko
test (sandbox): permintaan divalidasi dan tercatat, tetapi tidak ada email yang benar-benar dikirim, dan domain tidak perlu terverifikasi.Autentikasi & API key
Kirim API key di header Authorization: Bearer psv_live_…. Format key: psv_{live|test}_ + 32 karakter. Key disimpan sebagai hash — Postivo tidak bisa menampilkannya lagi, jadi simpan di secret manager, bukan di kode.
| Scope | Mengizinkan |
|---|---|
emails:send | Kirim, batch, cancel email; login SMTP |
emails:read | Daftar email, detail, event |
domains:manage | Tambah, verifikasi, ubah, hapus domain |
suppressions:manage | Kelola suppression list |
webhooks:manage | Kelola endpoint webhook |
api_keys:manage | Buat/cabut API key |
Praktik terbaik
emails:send untuk aplikasi biasa). Cabut key yang bocor dari halaman API Keys — efeknya langsung. Key live hanya bisa dibuat setelah email akun terverifikasi.{ "error": { "code": "unauthenticated", "message": "Invalid or missing API key.", "request_id": "9b2c…" } }
Menambah domain
Email hanya bisa dikirim dari domain milik organisasi Anda yang berstatus Active. Domain diambil dari alamat pada header From.
- Lewat console: Domains → Tambah. Lewat API:
POST /v1/domains(scopedomains:manage). - Gunakan subdomain khusus (mis.
mail.contoh.com) agar reputasi pengiriman transaksional terpisah dari domain utama. - Postivo membuat pasangan kunci DKIM RSA-2048 per domain. Kunci privat disimpan terenkripsi dan tidak pernah ditampilkan.
curl https://api.postivo.my.id/v1/domains \
-H "Authorization: Bearer $POSTIVO_API_KEY" -H "Content-Type: application/json" \
-d '{"domain":"mail.contoh.com"}'
Lima record DNS
Pasang record berikut di penyedia DNS domain Anda (Cloudflare, Niagahoster, dsb.). Nilai persisnya tampil di halaman domain — tombol salin tersedia.
| Record | Tipe · Host | Fungsi | Status |
|---|---|---|---|
| DKIM | TXT · postivo._domainkey.{domain} | Bukti email benar-benar ditandatangani domain Anda | Wajib |
| SPF | TXT · {domain} | Mengizinkan server Postivo: v=spf1 include:spf.postivo.my.id ~all | Wajib |
| Return-Path | CNAME · bounces.{domain} → bounce.postivo.my.id | Menerima bounce; membuat SPF/DMARC selaras | Wajib |
| DMARC | TXT · _dmarc.{domain} | Kebijakan autentikasi; mulai dari p=none | Disarankan |
| Tracking | CNAME · trk.{domain} → trk.postivo.my.id | Link/piksel tracking di domain Anda sendiri | Opsional |
Sudah punya SPF?
include:spf.postivo.my.id ke record yang ada — jangan membuat record kedua.DMARC bertahap
p=none dan pantau laporan 2–4 minggu, baru naikkan ke quarantine lalu reject.Verifikasi & status domain
Klik Verifikasi sekarang di console atau panggil POST /v1/domains/{id}/verify. Postivo juga mengaudit ulang semua domain otomatis setiap 15 menit.
| Status | Arti |
|---|---|
PENDING | Menunggu record wajib. Dicek otomatis; menjadi FAILED bila lewat 7 hari tanpa verifikasi. |
ACTIVE | DKIM, SPF, dan Return-Path lolos. Boleh mengirim. |
FAILED | Record wajib hilang/berubah. Pengiriman ditolak dengan domain_not_verified. Anda mendapat email peringatan. |
SUSPENDED | Dihentikan oleh Postivo (pelanggaran kebijakan). Hubungi support. |
Gangguan resolver DNS tidak dihitung sebagai record gagal: status record terakhir dipertahankan sampai pengecekan berikutnya berhasil.
Troubleshooting DNS
- Record sudah dipasang tapi belum terdeteksi — propagasi bisa sampai beberapa jam. Kolom “Terdeteksi” di halaman domain menampilkan apa yang benar-benar terbaca.
- Penyedia DNS menambahkan domain otomatis — banyak panel menambahkan
.{domain}sendiri. Jika host Anda menjadipostivo._domainkey.mail.contoh.com.mail.contoh.com, isi hanya bagian depan (postivo._domainkey). - Nilai DKIM terpotong — kunci publik panjang; sebagian panel meminta nilai dipecah dalam tanda kutip. Hasil akhirnya harus tetap satu string utuh.
- CNAME tidak bisa di apex — itulah alasan disarankan memakai subdomain.
- Cloudflare — set record CNAME ke DNS only (awan abu-abu), bukan proxied.
POST /v1/emails
Mengirim satu email ke satu atau beberapa penerima. Scope: emails:send.
| Field | Tipe | Keterangan |
|---|---|---|
from | string, wajib | "Nama <alamat@domain>" atau alamat saja. Domain harus Active. |
to | array, wajib | Alamat penerima. Maks 50 penerima gabungan to+cc+bcc. |
cc, bcc | array | Opsional. Penerima duplikat digabung. |
subject | string, wajib | Maks 255 karakter. |
html, text | string | Minimal salah satu wajib. Kirim keduanya untuk kompatibilitas terbaik. |
reply_to | string | Alamat balasan. |
headers | object | Header kustom. Header sistem (From, To, Subject, Message-ID, DKIM-Signature, dst.) diabaikan. |
attachments | array | Lihat Lampiran. |
tags, metadata | array / object | Lihat Jadwal, tag, metadata. |
track_opens, track_clicks | boolean | Bawaan false (atau bawaan domain). |
scheduled_at | ISO-8601 | Waktu kirim di masa depan. |
Setiap penerima menjadi satu dispatch terpisah dan menerima email sendiri (alamat penerima lain tidak terlihat). Penerima yang ada di suppression list ditandai SUPPRESSED dan tidak dikirimi; bila semua penerima suppressed, permintaan ditolak 422 recipient_suppressed.
{
"error": {
"code": "validation_failed",
"message": "The given data was invalid.",
"request_id": "9b2c…",
"details": { "to.0": ["The to.0 field must be a valid email address."] }
}
}
Pengiriman batch
POST /v1/emails/batch menerima {"emails": [ … ]} berisi 1–100 objek dengan skema yang sama seperti POST /v1/emails. Respons 207 Multi-Status memuat hasil per item sehingga satu item gagal tidak membatalkan yang lain. Satu Idempotency-Key berlaku untuk seluruh batch (diturunkan per indeks).
{ "results": [
{ "index": 0, "status": 202, "data": { "id": "0192…", "status": "queued" } },
{ "index": 1, "status": 422, "error": { "code": "validation_failed", "details": { "to.0": ["…"] } } }
] }
Lampiran
"attachments": [
{ "filename": "invoice.pdf", "content": "<base64>", "content_type": "application/pdf" }
]
- Maks 10 lampiran; total payload maks 25 MB. Konten harus base64 valid.
- Tipe berbahaya (
.exe .bat .cmd .scr .js .vbs .jar .msi .dll) ditolak pada jalur SMTP.
Idempotency
Kirim header Idempotency-Key: <nilai unik> agar retry jaringan tidak menghasilkan email ganda.
- Key sama + body sama →
200dengan respons email yang sudah dibuat (tidak dikirim lagi). - Key sama + body berbeda →
409 conflict. - Key berlaku per organisasi. Gunakan identitas kejadian, mis.
otp-{user_id}-{timestamp}.
Jadwal, tag, metadata
scheduled_at— kirim nanti. Email terjadwal masih bisa dibatalkan denganPOST /v1/emails/{id}/cancelselama berstatusQUEUED.tags— hingga 10 label (mis.["otp"]) untuk memfilter:GET /v1/emails?tag=otp.metadata— pasangan kunci-nilai bebas (mis.{"user_id":"8812"}) yang dikembalikan di respons dan di setiap payload webhook. Jangan menaruh data sensitif.
Open & click tracking
Tracking bersifat opt-in. Aktifkan per email (track_opens, track_clicks) atau sebagai bawaan per domain di console.
- Click — link
http(s)ditulis ulang ke/c/<token>lalu dialihkan (302). Link berhenti berlangganan milik sistem tidak ikut ditulis ulang. - Open — piksel GIF 1×1 di
/o/<token>.gif. - Pembuka otomatis (proxy privasi, scanner keamanan, crawler) terdeteksi dan diberi tanda
is_bot— jangan menganggapnya pembacaan manusia. - Pasang CNAME
trk.{domain}agar link memakai domain Anda.
Jangan untuk OTP & reset password
track_clicks mati untuk email sensitif.Kredensial & port SMTP
Pakai Postivo sebagai relay untuk aplikasi/CMS yang hanya mendukung SMTP (WordPress, Laravel Mail, Nodemailer, dst.).
| Host | smtp.postivo.my.id |
|---|---|
| Port | 587 STARTTLS (disarankan) · 465 TLS implisit · 2525 STARTTLS (alternatif bila 587 diblokir) |
| TLS | Wajib TLS 1.2+. AUTH hanya diterima setelah koneksi terenkripsi. |
| Username | Bebas (disarankan postivo) |
| Password | API key aktif dengan scope emails:send |
| Batas | 25 MB per pesan · 50 penerima per transaksi |
- Domain pengirim ditentukan oleh header
From;MAIL FROMamplop diabaikan (Postivo memakai Return-Path sendiri untuk menangkap bounce). - Penerima di amplop yang tidak tercantum di header
To/Ccdiperlakukan sebagai Bcc. - 10 kegagalan autentikasi dalam 10 menit dari satu IP memblokir sementara IP tersebut.
Kode balasan SMTP
Pesan dianggap diterima (250) hanya setelah tersimpan dan masuk antrean. Karena validasi berjalan sebelum balasan dikirim, penolakan datang dengan kode yang tepat.
| Kode | Arti | Tindakan klien |
|---|---|---|
235 | Autentikasi berhasil | — |
250 2.0.0 Ok: queued as <id> | Diterima & diantrekan | — |
535 5.7.8 | API key salah / dicabut / scope kurang | Periksa key |
550 5.7.1 | Domain From tidak Active atau bukan milik organisasi | Verifikasi domain |
550 5.1.1 | Semua penerima ada di suppression list | Jangan retry |
552 5.3.4 | Pesan melebihi 25 MB | Perkecil lampiran |
554 5.6.0 | Isi tidak valid (tanpa From/body, lampiran terlarang) | Perbaiki pesan |
452 4.5.3 | Kuota/batas harian habis atau terlalu banyak penerima | Retry nanti / upgrade paket |
451 4.3.0 | Gangguan sementara di sisi Postivo | Klien akan retry otomatis |
421 4.7.0 | Terlalu banyak gagal autentikasi | Tunggu ±10 menit |
Contoh koneksi
const transporter = nodemailer.createTransport({
host: 'smtp.postivo.my.id',
port: 587,
secure: false, // STARTTLS
requireTLS: true,
auth: { user: 'postivo', pass: process.env.POSTIVO_API_KEY },
});
MAIL_MAILER=smtp
MAIL_HOST=smtp.postivo.my.id
MAIL_PORT=587
MAIL_USERNAME=postivo
MAIL_PASSWORD=psv_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
[email protected]
import smtplib, ssl
from email.message import EmailMessage
msg = EmailMessage()
msg["From"], msg["To"], msg["Subject"] = "Acme <[email protected]>", "[email protected]", "Halo"
msg.set_content("Tes SMTP")
with smtplib.SMTP("smtp.postivo.my.id", 587) as s:
s.starttls(context=ssl.create_default_context())
s.login("postivo", "psv_live_…")
s.send_message(msg)
Siklus status
Setiap penerima punya satu status. Status hanya maju: event yang datang terlambat tidak bisa memundurkannya (mis. delivered setelah bounced diabaikan).
| Status | Arti |
|---|---|
QUEUED | Diterima, menunggu giliran kirim (atau waktu scheduled_at). |
SENDING | Sedang diserahkan ke relay. |
DEFERRED | Gangguan sementara; akan dicoba ulang dengan jeda 1m, 5m, 15m, 1j, 3j, 6j, 12j. |
SENT | Relay menerima pesan. |
DELIVERED | Server penerima menerima pesan (balasan 250). |
BOUNCED | Ditolak permanen oleh server penerima. |
COMPLAINED | Penerima menandai sebagai spam. |
FAILED | Gagal setelah semua retry, dibatalkan, atau kesalahan internal. |
SUPPRESSED | Dilewati karena ada di suppression list. |
opened, clicked, dan unsubscribed adalah event, bukan status — satu email bisa berstatus DELIVERED dan tetap menerima event opened berkali-kali.
Bounce & komplain
| Jenis | Penyebab | Perlakuan |
|---|---|---|
HARD | Alamat tidak ada / domain tidak valid (5xx) | Status BOUNCED; alamat masuk suppression. |
SOFT | Kotak penuh, gangguan sementara (4xx) | Dicoba ulang; tidak di-suppress. |
BLOCK | Ditolak karena reputasi/kebijakan pengirim | Status BOUNCED namun alamat tidak di-suppress (bukan salah alamat). |
| Komplain | Penerima menekan “spam” | Status COMPLAINED; alamat di-suppress. |
Jaga reputasi
Suppression list
Daftar alamat yang tidak akan dikirimi email dari organisasi Anda. Terisi otomatis oleh HARD_BOUNCE, COMPLAINT, dan UNSUBSCRIBE; Anda juga bisa menambah manual (MANUAL) atau menghapus entri bila perlu (console atau /v1/suppressions).
Pencocokan memakai alamat huruf kecil; titik dan +tag pada Gmail tidak dinormalisasi.
Berhenti berlangganan: sertakan header List-Unsubscribe Anda sendiri lewat field headers. Tautan /u/<token> milik Postivo mendukung one-click (RFC 8058) dan langsung men-suppress penerima.
Event & payload
Buat endpoint di Webhooks (HTTPS publik) dan pilih event. Postivo mengirim POST JSON setiap ada perubahan.
Tipe event: email.queued email.sent email.delivered email.deferred email.bounced email.complained email.failed email.suppressed email.opened email.clicked email.unsubscribed, atau * untuk semuanya.
{
"id": "evt_0192…",
"type": "email.delivered",
"created_at": "2026-10-27T08:15:32Z",
"data": {
"email_id": "0192…", "dispatch_id": "0192…",
"recipient": "[email protected]", "domain": "mail.contoh.com",
"tags": ["otp"], "metadata": { "user_id": "8812" },
"smtp_response": "250 2.0.0 OK", "bounce": null
}
}
Header: Postivo-Signature, Postivo-Event-Id, User-Agent: Postivo-Webhook/1.0. Endpoint harus membalas 2xx dalam 10 detik. Pengiriman bersifat at-least-once — jadikan handler idempoten pada Postivo-Event-Id.
Keamanan URL
localhost, jaringan privat, dan redirect ditolak (proteksi SSRF). Untuk uji lokal, gunakan tunnel HTTPS.Verifikasi tanda tangan
Header Postivo-Signature: t=<unix>,v1=<hex>, dengan v1 = HMAC_SHA256(secret, "{t}.{raw_body}"). Secret berformat whsec_… dan hanya tampil sekali saat endpoint dibuat. Gunakan body mentah (sebelum di-parse), bandingkan dengan waktu konstan, dan tolak bila |sekarang − t| > 5 menit (anti-replay).
import crypto from 'node:crypto';
app.post('/webhooks/postivo', express.raw({ type: 'application/json' }), (req, res) => {
const [t, v1] = req.get('Postivo-Signature').split(',').map((p) => p.split('=')[1]);
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return res.sendStatus(400);
const expected = crypto.createHmac('sha256', process.env.POSTIVO_WEBHOOK_SECRET)
.update(`${t}.${req.body.toString('utf8')}`).digest('hex');
const ok = expected.length === v1.length &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
if (!ok) return res.sendStatus(401);
const event = JSON.parse(req.body); // proses idempoten berdasarkan event.id
res.sendStatus(200);
});
$header = $request->header('Postivo-Signature'); // "t=…,v1=…"
parse_str(str_replace(',', '&', $header), $p);
$raw = $request->getContent();
abort_if(abs(time() - (int) $p['t']) > 300, 400);
$expected = hash_hmac('sha256', $p['t'].'.'.$raw, config('services.postivo.webhook_secret'));
abort_unless(hash_equals($expected, $p['v1']), 401);
import hmac, hashlib, time
from flask import request, abort
parts = dict(x.split("=", 1) for x in request.headers["Postivo-Signature"].split(","))
raw = request.get_data()
if abs(time.time() - int(parts["t"])) > 300: abort(400)
expected = hmac.new(SECRET.encode(), f"{parts['t']}.".encode() + raw, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, parts["v1"]): abort(401)
Retry & auto-disable
- Respons non-2xx atau timeout dicoba ulang dengan jeda 30 dtk, 2 mnt, 10 mnt, 1 jam, 6 jam, 24 jam.
- Setelah 50 kegagalan beruntun, endpoint dinonaktifkan otomatis dan Anda diberi tahu lewat email. Aktifkan kembali di halaman Webhooks setelah memperbaiki endpoint.
- Riwayat pengiriman terakhir (status HTTP, durasi) tampil di console.
Daftar endpoint
Base URL https://api.postivo.my.id/v1 · JSON UTF-8 · waktu ISO-8601 UTC. Setiap respons membawa X-Request-Id — sertakan saat melapor masalah.
| Method & path | Scope | Fungsi |
|---|---|---|
POST /emails | emails:send | Kirim email (header opsional Idempotency-Key) |
POST /emails/batch | emails:send | Kirim hingga 100 email, respons 207 |
GET /emails | emails:read | Daftar; filter status, tag, to, from_date, to_date, limit (1–100), cursor |
GET /emails/{id} | emails:read | Detail + penerima + event |
GET /emails/{id}/events | emails:read | Timeline event |
POST /emails/{id}/cancel | emails:send | Batalkan yang masih QUEUED |
GET /domains · POST /domains | domains:manage | Daftar / tambah domain |
GET /domains/{id} · PATCH · DELETE | domains:manage | Detail / ubah default tracking / hapus |
POST /domains/{id}/verify | domains:manage | Jalankan audit DNS sekarang |
GET /suppressions · POST · DELETE /{id} | suppressions:manage | Kelola suppression |
GET /webhooks · POST · PATCH /{id} · DELETE /{id} | webhooks:manage | Kelola webhook |
GET /api-keys · POST · DELETE /{id} | api_keys:manage | Kelola API key |
GET /ping | — | Cek ketersediaan API |
Pagination memakai cursor: respons daftar berisi {"data": […], "next_cursor": "…"}; kirim nilainya sebagai ?cursor= untuk halaman berikutnya.
Format & kode error
{ "error": { "code": "validation_failed", "message": "…", "request_id": "9b2c…", "details": { "field": ["…"] } } }
| HTTP | code | Penyebab |
|---|---|---|
| 400 | bad_request | JSON rusak |
| 401 | unauthenticated | Key hilang, salah, atau dicabut |
| 403 | forbidden · scope_missing | Izin kurang; organisasi ditangguhkan; key tak boleh memakai domain itu |
| 404 | not_found | Resource tidak ada / bukan milik organisasi |
| 409 | conflict | Domain sudah terdaftar; Idempotency-Key bentrok; email tak bisa dibatalkan |
| 413 | payload_too_large | Lebih dari 25 MB |
| 422 | validation_failed · domain_not_verified · recipient_suppressed | Data tidak valid; domain From belum Active; semua penerima suppressed |
| 429 | rate_limited · quota_exceeded | Terlalu cepat / kuota habis. Ada header Retry-After |
| 5xx | internal_error | Gangguan di sisi Postivo — aman di-retry dengan Idempotency-Key |
Rate limit & kuota
- Rate limit:
POST /emails20 permintaan/detik per API key; endpoint lain 10/detik. HeaderX-RateLimit-Limit,-Remaining,-Resetada di setiap respons. - Kuota bulanan & batas harian mengikuti paket. Hanya penerima yang benar-benar diproses yang dihitung (yang
SUPPRESSEDdan sandbox tidak). - Saat
429, tunggu sesuaiRetry-Afterlalu ulangi denganIdempotency-Keyyang sama. - Anda mendapat email peringatan saat kuota mencapai 80% dan 100%.
Paket & batas
| Paket | Harga / bulan | Kuota email / bulan | Batas harian |
|---|---|---|---|
| Free | Gratis | 3,000 | 100 |
| Starter | Rp 99.000 | 25,000 | Tanpa batas |
| Growth | Rp 299.000 | 100,000 | Tanpa batas |
| Scale | Rp 899.000 | 500,000 | Tanpa batas |
Kuota direset setiap awal bulan kalender. Batas per pesan: 25 MB, 50 penerima. Bila paket berbayar berakhir tanpa perpanjangan, akun otomatis kembali ke Free — data, domain, dan API key tetap aman.
Checkout & pembayaran
- Buka Billing di console, pilih paket, tentukan durasi (1/3/6/12 bulan).
- Klik Buat tagihan & bayar — Anda diarahkan ke halaman pembayaran aman Xendit.
- Pilih metode: QRIS, virtual account (BCA, BNI, BRI, Mandiri, Permata, CIMB), Indomaret/Alfamart, atau e-wallet.
- Setelah dibayar, paket aktif otomatis (lewat webhook; halaman tagihan juga memeriksa status langsung ke Xendit saat Anda kembali).
- Tagihan berlaku 24 jam. Yang kedaluwarsa bisa dibuat ulang tanpa biaya.
- Perpanjangan paket yang sama menyambung dari tanggal berakhir; ganti paket berlaku dari saat pembayaran.
- Hanya owner dan admin organisasi yang dapat membeli.
- Anda menerima email saat tagihan dibuat, saat pembayaran diterima, dan sebelum paket berakhir (7 dan 1 hari).
Email dari Postivo
Email sistem dikirim dari [email protected]; balasan diarahkan ke [email protected]. Pastikan keduanya tidak masuk filter spam Anda.
| Kapan dikirim | Penerima | |
|---|---|---|
| Selamat datang | Setelah pendaftaran | Pendaftar |
| Verifikasi email | Pendaftaran / kirim ulang | Pendaftar |
| Atur ulang kata sandi | Lupa kata sandi | Pemilik akun |
| Undangan tim | Admin mengundang anggota | Orang yang diundang |
| API key baru | Key dibuat (peringatan keamanan) | Pembuat key |
| Domain terverifikasi / bermasalah | Status domain berubah | Owner & admin |
| Kuota 80% / 100% | Pemakaian bulanan mencapai ambang | Owner & admin |
| Webhook dinonaktifkan | 50 kegagalan beruntun | Owner & admin |
| Tagihan dibuat / pembayaran diterima | Checkout dan konfirmasi Xendit | Owner & admin / pembayar |
| Paket akan berakhir / berakhir | 7 hari, 1 hari, dan saat berakhir | Owner & admin |
Keamanan & kepatuhan
- Transport: TLS 1.2+ untuk API dan SMTP. API key disimpan sebagai hash; kunci DKIM privat dan secret webhook dienkripsi.
- Isolasi: setiap organisasi hanya melihat data miliknya; key bisa dibatasi per domain.
- Retensi: isi email (HTML/teks) dihapus setelah 30 hari; event setelah 90 hari. Metadata ringkas tetap ada untuk audit.
- Penggunaan yang diizinkan: hanya email transaksional/berizin. Spam, daftar yang dibeli, phishing, dan konten ilegal berujung penangguhan akun.
- Melapor celah keamanan: [email protected] (jangan sertakan data pelanggan).
FAQ
Respons 202 tapi email tidak sampai?
202 hanya berarti diterima & diantrekan. Buka detail email di console: timeline menunjukkan sent, delivered, atau bounced lengkap dengan respons SMTP server penerima. Cek juga folder spam dan pastikan SPF/DKIM/DMARC hijau.
Berapa lama email sampai?
Umumnya hitungan detik. Angka “< 50 ms” pada materi kami hanya merujuk ke waktu API menerima & mengantrekan, bukan ke waktu sampai di inbox.
Bisa mengirim dari domain tanpa subdomain?
Bisa, tetapi subdomain khusus disarankan: reputasi terpisah dan CNAME Return-Path/Tracking tidak berbenturan dengan record utama.
Email ke satu penerima ditolak recipient_suppressed?
Alamat itu pernah bounce keras, komplain, atau berhenti berlangganan. Hapus dari Suppressions hanya bila Anda yakin masalahnya sudah selesai.
Bagaimana menguji tanpa mengirim email sungguhan?
Gunakan API key test (sandbox): validasi penuh dan event tercatat, tetapi tidak ada email yang keluar dan kuota tidak terpakai.
Kontak
Email [email protected] dengan menyertakan X-Request-Id atau ID email terkait.
