EmailReferensi REST API

Referensi REST API

Zeabur Email menyediakan REST API lengkap yang memudahkan Anda mengintegrasikan fungsi pengiriman email ke dalam aplikasi.

Autentikasi

Setiap permintaan API harus menyertakan API key (format Bearer Token) di header HTTP:

Authorization: Bearer zs_your_api_key_here

API key dapat dibuat dan dikelola di halaman manajemen Zeabur Email pada konsol Zeabur.

Base URL

https://api.zeabur.com/api/v1/zsend

Mengirim Email

Kirim Satu Email

Kirim email secara langsung.

POST /emails

Request Body

{
  "from": "sender@yourdomain.com",
  "to": ["recipient@example.com"],
  "cc": ["cc@example.com"],           // Opsional
  "bcc": ["bcc@example.com"],         // Opsional
  "reply_to": ["reply@yourdomain.com"], // Opsional
  "subject": "Email Subject",
  "html": "<h1>HTML Content</h1>",
  "text": "Plain text content",
  "attachments": [                    // Opsional
    {
      "filename": "document.pdf",
      "content": "base64_encoded_content",
      "content_type": "application/pdf"
    }
  ],
  "headers": {                        // Opsional
    "X-Custom-Header": "value"
  },
  "tags": {                           // Opsional
    "campaign": "newsletter",
    "user_id": "12345"
  }
}

Deskripsi Field

FieldTipeWajibDeskripsi
fromstringYaAlamat email pengirim, domain harus sudah terverifikasi
toarrayYaDaftar alamat email penerima
ccarrayTidakDaftar alamat email CC
bccarrayTidakDaftar alamat email BCC
reply_toarrayTidakDaftar alamat balasan (reply-to)
subjectstringYaSubjek email (maks. 998 karakter)
htmlstringTidak*Konten email dalam format HTML (maks. 5 MB)
textstringTidak*Konten email dalam format teks biasa (maks. 5 MB)
attachmentsarrayTidakDaftar lampiran (maks. 10, masing-masing hingga 10 MB)
headersobjectTidakHeader email kustom (maks. 50)
tagsobjectTidakTag kustom untuk kategorisasi dan pelacakan
⚠️

Setidaknya salah satu dari html atau text harus diisi. Jika keduanya diisi, klien email akan memprioritaskan versi HTML, sedangkan klien yang tidak mendukung HTML akan menampilkan versi teks biasa. Total penerima (to + cc + bcc) tidak boleh lebih dari 50.

Respons

{
  "id": "696de2c84210d814d66ee052",
  "message_id": "",
  "status": "pending"
}

Contoh

curl -X POST https://api.zeabur.com/api/v1/zsend/emails \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -d '{
    "from": "hello@yourdomain.com",
    "to": ["user@example.com"],
    "subject": "Welcome to Zeabur Email",
    "html": "<h1>Welcome!</h1><p>Thank you for using Zeabur Email.</p>"
  }'

Kirim Email dengan Lampiran

Konten lampiran harus di-encode dalam Base64:

// Contoh JavaScript
const fs = require('fs');
 
const fileContent = fs.readFileSync('document.pdf');
const base64Content = fileContent.toString('base64');
 
const response = await fetch('https://api.zeabur.com/api/v1/zsend/emails', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_API_KEY'
  },
  body: JSON.stringify({
    from: 'hello@yourdomain.com',
    to: ['user@example.com'],
    subject: 'Attachment Test',
    html: '<p>Please see the attachment</p>',
    attachments: [{
      filename: 'document.pdf',
      content: base64Content,
      content_type: 'application/pdf'
    }]
  })
});

Pengiriman Terjadwal

Jadwalkan Email

Jadwalkan email untuk dikirim pada waktu tertentu.

POST /emails/schedule

Request Body

Sama seperti pengiriman satu email, dengan tambahan field scheduled_at:

{
  "from": "sender@yourdomain.com",
  "to": ["recipient@example.com"],
  "cc": ["cc@example.com"],              // Opsional
  "bcc": ["bcc@example.com"],            // Opsional
  "reply_to": ["reply@yourdomain.com"],  // Opsional
  "subject": "Scheduled Email",
  "html": "<h1>HTML Content</h1>",
  "text": "Plain text content",
  "attachments": [],                     // Opsional
  "headers": {},                         // Opsional
  "tags": {},                            // Opsional
  "scheduled_at": "2026-01-25T10:00:00Z" // Wajib, format ISO 8601
}

Waktu scheduled_at harus berada di masa mendatang. Semua field lainnya mengikuti aturan yang sama dengan pengiriman satu email.

Respons

{
  "id": "696de2c84210d814d66ee053",
  "status": "enqueued"
}

Daftar Email Terjadwal

GET /emails/scheduled

Parameter Query

ParameterTipeDeskripsi
pagenumberNomor halaman (default 1)
limitnumberJumlah item per halaman (default 20, maks. 100)
statusstringFilter berdasarkan status: scheduled, sent, cancelled

Respons

{
  "scheduled_emails": [
    {
      "id": "696de2c84210d814d66ee053",
      "from": "hello@yourdomain.com",
      "to": ["user@example.com"],
      "subject": "Scheduled Email",
      "scheduled_at": "2026-01-25T10:00:00Z",
      "status": "enqueued",
      "created_at": "2026-01-20T08:00:00Z",
      "attempts": 0
    }
  ],
  "total_count": 1
}

Detail Email Terjadwal

GET /emails/scheduled/:id

Batalkan Email Terjadwal

DELETE /emails/scheduled/:id

Respons

{
  "success": true,
  "message": "Scheduled email cancelled"
}

Pengiriman Massal

Kirim Email Secara Massal

Kirim banyak email sekaligus, dengan penerima dan konten yang berbeda untuk setiap email.

POST /emails/batch

Request Body

{
  "emails": [
    {
      "from": "hello@yourdomain.com",
      "to": ["user1@example.com"],
      "cc": ["manager@example.com"],       // Opsional
      "bcc": ["archive@example.com"],      // Opsional
      "reply_to": ["support@yourdomain.com"], // Opsional
      "subject": "Personalized Email 1",
      "html": "<p>Hello, User 1!</p>",
      "text": "Hello, User 1!",            // Opsional
      "attachments": [],                   // Opsional
      "headers": {},                       // Opsional
      "tags": {"user_id": "1"}             // Opsional
    },
    {
      "from": "hello@yourdomain.com",
      "to": ["user2@example.com"],
      "subject": "Personalized Email 2",
      "html": "<p>Hello, User 2!</p>"
    }
    // ... hingga 100 email
  ]
}

Satu kali pengiriman massal mendukung hingga 100 email. Setiap email mendukung semua field yang sama dengan pengiriman satu email, termasuk cc, bcc, reply_to, attachments, headers, dan tags.

Respons

{
  "job_id": "696de2c84210d814d66ee054",
  "status": "pending",
  "total_count": 2
}

Deskripsi Field

FieldTipeDeskripsi
job_idstringID job massal untuk memeriksa status dan detail di kemudian hari
statusstringStatus awal job (biasanya pending)
total_countnumberTotal jumlah email dalam job massal

job_id adalah pengenal unik untuk job massal, berbeda dengan id pada pengiriman satu email. Simpan job_id ini untuk memeriksa progres dan hasil pengiriman massal di kemudian hari.

Daftar Job Massal

GET /emails/batch

Parameter Query

Sama seperti daftar email terjadwal.

Detail Job Massal

GET /emails/batch/:id

Respons

{
  "job_id": "696de2c84210d814d66ee054",
  "total_count": 100,
  "sent_count": 95,
  "failed_count": 5,
  "status": "completed",
  "created_at": "2026-01-20T08:00:00Z",
  "completed_at": "2026-01-20T08:15:00Z"
}

Deskripsi Field

FieldTipeDeskripsi
job_idstringID job massal (sama dengan job_id yang dikembalikan saat pembuatan)
total_countnumberTotal jumlah email dalam job
sent_countnumberJumlah email yang berhasil dikirim
failed_countnumberJumlah email yang gagal
statusstringStatus job: pending, processing, completed, failed
created_atstringWaktu pembuatan job (format ISO 8601)
completed_atstringWaktu job selesai (opsional)

Kueri Email

Daftar Email

GET /emails

Parameter Query

ParameterTipeDeskripsi
pagenumberNomor halaman (default 1)
page_sizenumberJumlah item per halaman (default 20, maks. 100)
statusstringFilter berdasarkan status: pending, sent, delivered, bounced, complained
job_typestringFilter berdasarkan sumber: direct, scheduled, batch
job_idstringFilter berdasarkan ID job (ID email terjadwal atau ID job massal)

Respons

{
  "data": [
    {
      "id": "696de2c84210d814d66ee052",
      "from": "hello@yourdomain.com",
      "to": ["user@example.com"],
      "subject": "Test Email",
      "status": "delivered",
      "created_at": "2026-01-20T08:00:00Z"
    }
  ],
  "total": 1
}

Detail Email

GET /emails/:id

Respons

{
  "id": "696de2c84210d814d66ee052",
  "message_id": "0111019bd53de187-bda14a71-25a3-4fdc-a1a0-f543ff58c085-000000",
  "from": "hello@yourdomain.com",
  "to": ["user@example.com"],
  "cc": [],
  "bcc": [],
  "reply_to": [],
  "subject": "Test Email",
  "html": "<h1>Test</h1>",
  "text": "Test",
  "status": "delivered",
  "mal_status": "healthy",
  "created_at": "2026-01-20T08:00:00Z",
  "headers": {},
  "tags": {},
  "attachments": [],
  "job_type": "direct",
  "job_id": ""
}
FieldTipeDeskripsi
job_typestringSumber email: direct (pengiriman tunggal), scheduled (pengiriman terjadwal), batch (pengiriman massal)
job_idstringID job. Kosong untuk email langsung; berisi ID email terjadwal atau ID job massal untuk lainnya

Penanganan Error

API menggunakan kode status HTTP standar:

Kode StatusDeskripsi
200Permintaan berhasil
400Parameter permintaan tidak valid
401Tidak terotorisasi (API key tidak valid atau tidak ada)
403Akses ditolak (izin tidak mencukupi atau akun ditangguhkan)
404Resource tidak ditemukan
429Terlalu banyak permintaan (rate limit)
500Error internal server

Format Respons Error

{
  "error": "Brief error description",
  "message": "Detailed error message"
}

Contoh Error Umum

Error Validasi (400)

{
  "error": "validation error",
  "message": "subject length (1200) exceeds maximum (998 characters)"
}

Error Autentikasi (401)

{
  "error": "unauthorized",
  "message": "Invalid or missing API key"
}

Error Izin (403)

{
  "error": "permission denied",
  "message": "API key does not have permission to send from this domain"
}

Error Kuota Terlampaui (429)

{
  "error": "daily quota exceeded (55/55), resets at 2026-01-23 00:00:00"
}

Deskripsi:

  • Kode status: 429 Too Many Requests
  • Pesan error mencakup pemakaian saat ini, total kuota, dan waktu reset
  • Pengguna tetap dapat memeriksa riwayat email, tetapi tidak dapat mengirim email baru
  • Kuota di-reset secara otomatis setiap hari pukul 00:00 UTC

Batasan

Untuk kuota pengiriman bulanan per paket, harga kelebihan, dan cara penagihan kelebihan, lihat Kuota & Tagihan Kelebihan.

Batas Kuota Harian

Setiap akun pengguna memiliki kuota pengiriman harian (Daily Quota), yang merupakan batasan paling penting:

Tingkat AkunKuota Harian DefaultDeskripsi
Pengguna Baru100 email/hariKuota awal setelah akun dibuat
Terverifikasi1.000 email/hariDitingkatkan secara otomatis setelah verifikasi domain

Waktu Reset Kuota: Di-reset secara otomatis setiap hari pukul 00:00 UTC

Saat Kuota Terlampaui:

  • Mengembalikan kode status: 429 Too Many Requests
  • Pesan error: daily quota exceeded (current/total), resets at time
  • Operasi baca tetap tersedia: Anda tetap dapat memeriksa riwayat dan detail email
  • Operasi kirim ditolak: Termasuk pengiriman tunggal, terjadwal, dan massal

Batasan Konten

  • Jumlah penerima: Maks. 50 penerima per email (to + cc + bcc)
  • Ukuran email: Maks. ukuran total 10 MB (termasuk lampiran dan header)
  • Jumlah lampiran: Maks. 10 lampiran
  • Ukuran satu lampiran: Maks. 10 MB
  • Panjang subjek: Maks. 998 karakter
  • Konten HTML: Maks. 5 MB
  • Konten teks: Maks. 5 MB
  • Pengiriman massal: Maks. 100 email per batch

Batasan Status Pengguna

Status akun pengguna memengaruhi akses API:

StatusAkses APIKirim EmailKueri EmailDeskripsi
healthy✅✅✅Status normal, dapat mengirim email
review✅✅✅Sedang ditinjau, masih dapat mengirim (kuota dapat dikurangi)
paused✅❌ (403)✅Ditangguhkan, dapat melakukan kueri tetapi tidak dapat mengirim
banned❌ (401)❌❌Diblokir, sepenuhnya dilarang mengakses API

Alasan Penangguhan/Pemblokiran Akun:

  • Bounce Rate ≥ 4,0%
  • Complaint Rate ≥ 0,08%
  • Pelanggaran ketentuan layanan

Penjelasan Status:

  • review (Sedang Ditinjau): Terdeteksi masalah kualitas email, sistem secara otomatis menandai akun untuk ditinjau. Jika tidak ada perilaku berbahaya lebih lanjut dalam 24 jam, status dapat pulih secara otomatis menjadi healthy.
  • paused (Ditangguhkan): Sementara dilarang mengirim, tetapi masih dapat memeriksa data riwayat, mengelola domain, dan sebagainya. Anda perlu menghubungi tim dukungan untuk mengajukan banding; pemulihan tercepat adalah 24 jam setelah banding disetujui.
  • banned (Diblokir): Sepenuhnya dilarang mengakses API, termasuk operasi kueri. Status ini ditetapkan secara manual oleh staf, menandakan pelanggaran serius, dan umumnya tidak dapat dipulihkan.
⚠️

Permintaan yang melampaui batasan akan mengembalikan error 400 Bad Request. Kuota yang terlampaui akan mengembalikan 429 Too Many Requests.


Praktik Terbaik

1. Percobaan Ulang saat Error

Untuk error sementara (seperti 500 atau 429), disarankan menggunakan percobaan ulang dengan exponential backoff:

async function sendEmailWithRetry(emailData, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      const response = await fetch('https://api.zeabur.com/api/v1/zsend/emails', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': 'Bearer YOUR_API_KEY'
        },
        body: JSON.stringify(emailData)
      });
      
      if (response.ok) {
        return await response.json();
      }
      
      if (response.status === 400 || response.status === 403) {
        // Error dari sisi klien, jangan coba ulang
        throw new Error(await response.text());
      }
      
      // Error lainnya, coba ulang setelah menunggu
      if (i < maxRetries - 1) {
        await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
      }
    } catch (error) {
      if (i === maxRetries - 1) throw error;
    }
  }
}

2. Gunakan Pengiriman Massal

Saat mengirim banyak email, gunakan endpoint pengiriman massal alih-alih melakukan pengiriman tunggal secara berulang:

// ✅ Disarankan
await fetch('https://api.zeabur.com/api/v1/zsend/emails/batch', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer YOUR_API_KEY'
  },
  body: JSON.stringify({
    emails: users.map(user => ({
      from: 'newsletter@yourdomain.com',
      to: [user.email],
      subject: `Hello, ${user.name}`,
      html: `<p>Personalized content</p>`
    }))
  })
});
 
// ❌ Tidak disarankan
for (const user of users) {
  await fetch('https://api.zeabur.com/api/v1/zsend/emails', {
    // ... pengiriman tunggal
  });
}

3. Gunakan Webhook

Konfigurasikan Webhook untuk menerima pembaruan status email secara real-time alih-alih melakukan polling ke endpoint kueri. Lihat Konfigurasi Webhook untuk detailnya.

4. Gunakan Tag dengan Tepat

Gunakan field tags untuk menandai email agar lebih mudah dilacak dan dianalisis:

{
  "tags": {
    "campaign": "welcome_series",
    "user_segment": "new_users",
    "template_version": "v2"
  }
}