REST API — Kirim Email

Satu endpoint untuk mengirim email: POST /v1/messages. Kirim JSON dengan API key akun Anda, dan Hubina menangani validasi sender, saldo, pengiriman, serta pencatatan status.

Base URL

base url
https://api.hubina.net/v1

REST API hanya dilayani dari host api.hubina.net. Semua respons berformat JSON dan dikirim denganCache-Control: no-store.

Autentikasi

Setiap permintaan kirim memakai API key di header Authorization:

http
Authorization: Bearer hb_live_YOUR_API_KEY
Content-Type: application/json

Key yang tidak valid atau sudah dicabut dibalas 401 tanpa detail tambahan. Cara membuat key ada di Autentikasi & API Key.

POST /v1/messages

Mengirim satu email; satu penerima maupun beberapa sekaligus (maksimum 50 alamat per permintaan).

Parameter request

FieldTipeWajibKeterangan
fromstringyaAlamat pengirim. Domainnya harus milik akun Anda dan berstatus terverifikasi.
tostring | string[]yaSatu alamat atau array alamat. Maksimum 50 alamat. Setiap alamat divalidasi formatnya.
subjectstringyaSubjek, maksimum 998 karakter, tidak boleh kosong.
textstringsalah satuIsi versi teks biasa. Maksimum 1.000.000 karakter.
htmlstringsalah satuIsi versi HTML. Maksimum 1.000.000 karakter. Boleh dikirim bersama text.
rawstringtidakPesan MIME lengkap (header + body) yang diteruskan apa adanya ke penyedia. Pakai hanya bila Anda memang menyusun MIME sendiri.

Minimal salah satu dari text, html, atau raw harus ada. Field internal Hubina (user_id, rate, cost, dan sejenisnya) akan ditolak jika ikut dikirim.

Contoh permintaan

curl
curl -X POST https://api.hubina.net/v1/messages \
  -H "Authorization: Bearer hb_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: invoice-2211-kwitansi" \
  -d '{
    "from": "[email protected]",
    "to": ["[email protected]", "[email protected]"],
    "subject": "Kwitansi pesanan #2211",
    "text": "Terima kasih, pesanan Anda sedang diproses.",
    "html": "<p>Terima kasih, pesanan <strong>#2211</strong> sedang diproses.</p>"
  }'
Node.js (fetch)
const response = await fetch('https://api.hubina.net/v1/messages', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.HUBINA_API_KEY}`,
    'Content-Type': 'application/json',
    'Idempotency-Key': `invoice-${invoice.id}-kwitansi`,
  },
  body: JSON.stringify({
    from: '[email protected]',
    to: [customer.email],
    subject: `Kwitansi pesanan ${invoice.id}`,
    text: 'Terima kasih, pesanan Anda sedang diproses.',
  }),
});

if (!response.ok) {
  const problem = await response.json();
  throw new Error(`Hubina ${response.status} ${problem.error}: ${problem.message}`);
}

const message = await response.json();
console.log('diterima untuk dikirim:', message.id, message.status);

Respons sukses

Permintaan yang valid dan berhasil diserahkan dibalas 202 Accepted:

202
{
  "id": "msg_1a2b3c4d5e6f77889900aabbccddeeff",
  "status": "accepted"
}

Jika permintaan yang sama diulang dengan Idempotency-Key yang sama, respons mengembalikan pesan yang sudah ada dan menandai duplicate: true — saldo tidak dipotong dua kali:

202 (duplikat)
{
  "id": "msg_1a2b3c4d5e6f77889900aabbccddeeff",
  "status": "accepted",
  "duplicate": true
}

Idempotency dan retry

Header Idempotency-Key mengikat satu permintaan logis ke satu pesan. Formatnya 8–200 karakter, diawali huruf/angka, boleh berisi huruf, angka, titik, garis bawah, titik dua, dan tanda hubung. Pakai nilai stabil dari domain Anda, misalnya order-10231-receipt.

SituasiHasil
Key sama, payload sama202 dengan duplicate: true; pesan lama dikembalikan, tanpa tagihan baru
Key sama, payload berbeda409 billing_conflict — key sudah terpakai untuk isi lain
Key sama yang sebelumnya gagal dan dananya sudah dikembalikan409 billing_conflict — buat key baru untuk percobaan baru
Tanpa headerPesan baru tanpa proteksi duplikat; request ulang bisa terkirim dua kali

Kapan boleh retry

  • 429 dan 503: boleh diulang dengan jeda bertahap (backoff), pakai Idempotency-Key yang sama.
  • 400 dan 403: perbaiki permintaan dulu — mengulang persis sama akan gagal lagi.
  • Timeout tanpa balasan: ulangi dengan Idempotency-Key yang sama agar aman dari kiriman ganda.

Rate limit

Permintaan kirim dibatasi 60 permintaan per menit per kombinasi akun + API key. Melebihi batas menghasilkan 429 beserta retryAfter (detik):

429
{
  "error": "rate_limited",
  "message": "Terlalu banyak permintaan.",
  "retryAfter": 17
}

Kode error

StatuserrorArtinyaYang harus dilakukan
400invalid_requestJSON tidak valid, field wajib kosong, penerima tidak valid, subjek/isi melebihi batas, atau body terlalu besarPerbaiki payload. Pesan message menyebut field-nya.
401unauthorizedAPI key tidak ada, salah, atau dicabutCek header Authorization; buat key baru bila perlu.
403sender_not_authorizedDomain pengirim bukan milik akun ini atau belum terverifikasiVerifikasi domain di dashboard, atau pakai alamat dari domain yang sudah terverifikasi.
403insufficient_balanceSaldo tersedia kurang dari rate akunTop up saldo.
409billing_conflictIdempotency-Key sudah dipakai untuk payload lain, atau sebelumnya sudah gagalPakai key baru untuk permintaan baru.
429rate_limitedMelebihi 60 permintaan per menitTunggu sesuai retryAfter.
503provider_unavailablePenyedia pengiriman sedang tidak bisa dihubungiRetry dengan backoff; tidak ada tagihan untuk percobaan yang gagal total.
500server_errorKesalahan tak terduga di sisi HubinaRetry dengan Idempotency-Key yang sama; hubungi dukungan bila berulang.

Batas yang berlaku

  • Penerima: maksimum 50 alamat per permintaan.
  • Subjek: maksimum 998 karakter. Isi: maksimum 1.000.000 karakter per bagian (text dan html masing-masing).
  • Body JSON: maksimum 2 MB. Untuk pesan lebih besar (sampai 10 MB) gunakan SMTP submission.
  • Rate limit: 60 permintaan per menit per akun + key.

Status akhir tidak ada di sini Respons 202 tidak memuat status akhir pengiriman. Pantau Sending & Logs di dashboard untuk melihat delivered, bounced, atau rejected.

Di halaman ini