04 — API: Membership & Billing
Endpoint untuk subscription plans, pembayaran, dan manajemen keanggotaan.
Subscription Plans
GET /membership/plans
Ambil semua paket berlangganan yang tersedia.
Access: Public
// Response 200
{
"success": true,
"data": [
{
"id": "plan_monthly",
"name": "Monthly",
"nameId": "Bulanan",
"description": "Akses penuh selama 1 bulan",
"period": "monthly",
"priceIdr": 99000,
"originalPriceIdr": null,
"priceFormatted": "Rp 99.000",
"pricePerDay": "Rp 3.300/hari",
"isPopular": true,
"features": {
"unlimitedAssessment": true,
"unlimitedPractice": true,
"personalBlueprint": true,
"dailyMissions": true,
"progressTracking": true,
"prioritySupport": false
},
"featureList": [
"Assessment tanpa batas",
"Latihan speaking tanpa batas",
"Blueprint belajar personal",
"Misi harian yang adaptif",
"Tracking progress lengkap"
]
},
{
"id": "plan_yearly",
"name": "Yearly",
"nameId": "Tahunan",
"description": "Akses penuh selama 1 tahun — hemat 33%!",
"period": "yearly",
"priceIdr": 799000,
"originalPriceIdr": 1188000,
"priceFormatted": "Rp 799.000",
"pricePerDay": "Rp 2.189/hari",
"savingsPercent": 33,
"isPopular": false,
"features": {
"unlimitedAssessment": true,
"unlimitedPractice": true,
"personalBlueprint": true,
"dailyMissions": true,
"progressTracking": true,
"prioritySupport": true
},
"featureList": [
"Semua fitur Monthly",
"Priority support",
"Hemat 33% dibanding bulanan"
]
}
]
}
Subscribe & Payment
POST /membership/subscribe
Mulai proses berlangganan — buat order dan redirect ke payment gateway.
Access: Authenticated
// Request Body
{
"planId": "plan_monthly",
"paymentMethod": "gopay" // Opsional: pre-select method
}
// Response 201
{
"success": true,
"data": {
"orderId": "ord_V1StGXR8_Z5j",
"planId": "plan_monthly",
"amount": 99000,
"currency": "IDR",
"status": "pending",
// Midtrans Snap redirect
"payment": {
"redirectUrl": "https://app.midtrans.com/snap/v4/...",
"token": "snap_token_xxx",
"expiresAt": "2026-09-20T16:30:00Z"
}
}
}
POST /membership/webhook/midtrans
Webhook dari Midtrans saat pembayaran berhasil/gagal.
Access: Midtrans Server (diverifikasi via signature)
// Request Body (dari Midtrans)
{
"transaction_status": "settlement",
"order_id": "ord_V1StGXR8_Z5j",
"gross_amount": "99000.00",
"payment_type": "gopay",
"transaction_id": "midtrans_txn_xxx",
"signature_key": "xxx"
}
// Response 200 (acknowledgment ke Midtrans)
{
"status": "ok"
}
Proses di Backend setelah webhook:
- Verifikasi signature dari Midtrans
- Update status payment →
paid - Buat/extend subscription →
active - Update user tier →
member - Kirim email konfirmasi
- Log ke audit_logs
Subscription Management
GET /membership/subscription
Ambil status subscription user saat ini.
Access: Authenticated
// Response 200 (Active member)
{
"success": true,
"data": {
"id": "sub_V1StGXR8_Z5j",
"plan": {
"id": "plan_monthly",
"name": "Monthly",
"period": "monthly"
},
"status": "active",
"startsAt": "2026-09-01T00:00:00Z",
"expiresAt": "2026-10-01T00:00:00Z",
"daysRemaining": 11,
"autoRenew": true,
"nextBillingDate": "2026-10-01T00:00:00Z",
"nextBillingAmount": 99000
}
}
// Response 200 (Free user / no subscription)
{
"success": true,
"data": null
}
POST /membership/subscription/cancel
Batalkan subscription (tidak langsung berhenti, tetap aktif sampai expired).
Access: Authenticated
// Request Body
{
"reason": "too_expensive", // Opsional
"feedback": "Saat ini budget saya terbatas" // Opsional
}
// Response 200
{
"success": true,
"data": {
"id": "sub_V1StGXR8_Z5j",
"status": "cancelled",
"activeUntil": "2026-10-01T00:00:00Z",
"message": "Subscription berhasil dibatalkan. Kamu masih bisa menggunakan fitur Member sampai 1 Oktober 2026."
}
}
POST /membership/subscription/reactivate
Aktifkan kembali subscription yang sudah di-cancel (sebelum expired).
Access: Authenticated
// Response 200
{
"success": true,
"data": {
"id": "sub_V1StGXR8_Z5j",
"status": "active",
"autoRenew": true,
"message": "Subscription berhasil diaktifkan kembali!"
}
}
Payment History
GET /membership/payments
Ambil riwayat pembayaran user.
Access: Authenticated
// Response 200
{
"success": true,
"data": [
{
"id": "pay_abc123",
"amount": 99000,
"currency": "IDR",
"amountFormatted": "Rp 99.000",
"status": "paid",
"paymentMethod": "gopay",
"planName": "Monthly",
"paidAt": "2026-09-01T10:00:00Z",
"invoiceUrl": "https://api.eljoy.id/api/v1/membership/invoices/pay_abc123"
},
{
"id": "pay_def456",
"amount": 99000,
"currency": "IDR",
"amountFormatted": "Rp 99.000",
"status": "paid",
"paymentMethod": "bca_va",
"planName": "Monthly",
"paidAt": "2026-08-01T09:30:00Z",
"invoiceUrl": "https://api.eljoy.id/api/v1/membership/invoices/pay_def456"
}
],
"pagination": { ... }
}
GET /membership/invoices/:paymentId
Download invoice PDF.
Access: Authenticated
Response: application/pdf
Content-Disposition: attachment; filename="invoice-ELJ-20260901.pdf"
Access Control
GET /membership/access
Cek apakah user boleh mengakses fitur tertentu.
Access: Authenticated
// Query: ?feature=unlimited_practice
// Response 200
{
"success": true,
"data": {
"feature": "unlimited_practice",
"hasAccess": false,
"reason": "free_tier",
"upgradeUrl": "/membership/plans",
"message": "Upgrade ke Member untuk latihan speaking tanpa batas!"
}
}
Feature list yang bisa dicek:
| Feature | Free | Member |
|---|---|---|
ice_breaker_assessment | ✅ (1x) | ✅ Unlimited |
universal_assessment | ✅ (1x) | ✅ Unlimited |
adaptive_assessment | ❌ | ✅ |
unlimited_practice | ❌ | ✅ |
personal_blueprint | ❌ | ✅ |
daily_missions | ❌ | ✅ |
progress_tracking | ❌ | ✅ |
conversation_history | ❌ | ✅ |