Change Plan API
Plan Change Preview
Integration Guide
Apa Itu Upgrade atau Downgrade Subscription?
Ubah plan subscription pelanggan untuk memindahkan mereka antar-tier, menyesuaikan quantity untuk produk berbasis seat, atau memigrasikan mereka ke produk baru. API secara otomatis menghitung prorasi dan biaya berdasarkan billing mode yang Anda pilih.Kapan Menggunakan Perubahan Plan
- Upgrade when a customer needs more features, usage, or seats
- Downgrade when usage decreases
- Migrate users to a new product or price without cancelling their subscription
Plan Change Flow
Prerequisites
Before implementing subscription plan changes, ensure you have:- A Dodo Payments merchant account with active subscription products
- API credentials (API key and webhook secret key) from the dashboard
- An existing active subscription to modify
- Webhook endpoint configured to handle subscription events
Step-by-Step Implementation Guide
Follow this comprehensive guide to implement subscription plan changes in your application:Understand Plan Change Requirements
- Which subscription products can be changed to which others
- What proration mode fits your business model
- How to handle failed plan changes gracefully
- Which webhook events to track for state management
Choose Your Proration Strategy
- prorated_immediately
- difference_immediately
- full_immediately
- do_not_bill
- Mengkreditkan bagian yang tidak terpakai dari siklus saat ini, diprorata berdasarkan waktu yang tersisa
- Kemudian menagih satu siklus penuh pada plan baru — harga plan baru tidak pernah diprorata
- Biaya bersih = siklus baru penuh − (fraksi yang tersisa × siklus lama penuh)
Implement the Change Plan API
prorated_immediately, full_immediately, difference_immediately, atau do_not_bill.null, atau mengirim array kosong akan menghapus add-on yang sudah ada, jadi sertakan add-on saat ini untuk mempertahankannya.prevent_change: Pertahankan langganan pada paket saat ini hingga pembayaran berhasilapply_change(default): Terapkan perubahan paket segera terlepas dari hasil pembayaran
allow_plan_change_via_payment_link milik bisnis (Settings → Subscriptions → Collect Plan Change Payments by Payment Link), effective_at: immediately, dan on_payment_failure: prevent_change. Lihat Collecting Payment via a Checkout Link. Diabaikan oleh preview route.subscription_id, payment_id, dan status. Memerlukan collect_via_payment_link: true; jika tidak, request gagal dengan 422. Lihat Mengalihkan Pelanggan Setelah Pembayaran.409. Lihat Mengganti Payment Link yang Tertunda. Diabaikan oleh route preview.- Tidak diberikan /
null— diskon yang ada denganpreserve_on_plan_change=truedipertahankan jika berlaku untuk produk baru. [](array kosong) — menghapus semua diskon yang ada dari langganan.["CODE_A", "CODE_B", ...]— mengganti semua diskon yang ada dengan set stacked ini.
discount_codes untuk integrasi baru. Field ini masih berfungsi untuk kompatibilitas mundur, tetapi tidak dapat digabungkan dengan discount_codes dalam request yang sama.immediately(default): Terapkan perubahan paket segeranext_billing_date: Jadwalkan perubahan pada tanggal penagihan berikutnya. Pelanggan mempertahankan paket saat ini hingga periode penagihan berakhir. Gunakan ini untuk downgrade agar pelanggan tetap memperoleh manfaat paket saat ini hingga akhir periode penagihan.
Handle Webhook Events
subscription.active: Perubahan paket berhasil, langganan diperbaruisubscription.plan_changed: Paket langganan berubah (upgrade/downgrade/pembaruan addon)subscription.on_hold: Tagihan perubahan paket gagal, renewal dihentikanpayment.succeeded: Tagihan langsung untuk perubahan paket berhasilpayment.failed: Tagihan langsung gagal
Update Your Application State
- Berikan/cabut fitur berdasarkan paket baru
- Perbarui dashboard pelanggan dengan detail paket baru
- Kirim email konfirmasi tentang perubahan paket
- Catat perubahan penagihan untuk keperluan audit
Test and Monitor
- Uji semua mode proration dengan berbagai skenario
- Verifikasi bahwa penanganan webhook berfungsi dengan benar
- Pantau tingkat keberhasilan perubahan paket
- Siapkan alert untuk perubahan paket yang gagal
Preview Perubahan Paket
Sebelum menetapkan perubahan paket, gunakan Preview API untuk menunjukkan kepada pelanggan jumlah yang akan ditagihkan secara tepat:- Node.js SDK
- Python SDK
immediate_charge.summary, customer_credits adalah perubahan bersih pada saldo kredit pelanggan, dalam mata uang yang diberikan oleh customer_credits_currency. Ini adalah mata uang credit wallet pelanggan, yaitu mata uang langganan. Mata uang ini dapat berbeda dari currency pada ringkasan, yang berlaku untuk total_amount dan tax. Misalnya, pelanggan yang membayar dalam INR untuk langganan USD akan melihat kredit dalam USD.Change Plan API
Gunakan Change Plan API untuk mengubah produk, kuantitas, dan perilaku proration pada langganan aktif.Contoh Quick Start
- Node.js SDK
- Python SDK
- Go SDK
- HTTP
200 OK segera — sebelum tagihan benar-benar diselesaikan. Isi body (ChangePlanResponse) bergantung pada cara perubahan tersebut ditagihkan:
collect_via_payment_link, langganan tetap menggunakan paket saat ini hingga pelanggan menyelesaikan pembayaran.Konfirmasikan hasilnya melalui webhook (payment.succeeded, payment.failed, subscription.plan_changed) atau dengan membaca ulang langganan menggunakan GET /subscriptions/{subscription_id} — lihat Yang Terjadi Saat Link Belum Dibayar untuk kasus payment link.Mengumpulkan Pembayaran melalui Checkout Link
Secara default, perubahan paket langsung menagih metode pembayaran tersimpan milik langganan. Aturcollect_via_payment_link: true untuk mengarahkan pelanggan ke halaman checkout yang di-host — berguna jika tidak ada metode pembayaran tersimpan atau Anda ingin pelanggan mengonfirmasi harga baru secara aktif.
Persyaratan
collect_via_payment_link: true hanya berhasil jika semua kondisi berikut terpenuhi — jika tidak, request gagal dengan 422:
- Bisnis mengaktifkan capability
allow_plan_change_via_payment_link(Settings → Subscriptions → Collect Plan Change Payments by Payment Link). effective_atadalahimmediately(default). Perubahan terjadwal (next_billing_date) tidak pernah memerlukan halaman checkout.- Request menetapkan
on_payment_failure: prevent_change.apply_changeyang eksplisit gagal dengan422.
collect_via_payment_link berlaku untuk setiap perubahan langsung yang menghasilkan tagihan, termasuk downgrade, selama persyaratan di atas terpenuhi.payment_link dan field checkout lainnya dikembalikan sebagai null, dan perubahan diterapkan segera. Ini bukan 422. Panggil Preview Plan Change terlebih dahulu untuk memeriksa jumlah sebelum meminta link.
- Node.js SDK
- Python SDK
- HTTP
Yang Terjadi Saat Link Belum Dibayar
- Langganan tetap menggunakan paket saat ini —
product_id,recurring_pre_tax_amount, dannext_billing_datesemuanya tidak berubah hingga link dibayar. - Request
change-planberikutnya ditolak dengan409 PendingPlanChangeExistssaat link masih tertunda. Untuk mengganti perubahan yang tertunda, kirim request baru dengancancel_older_payment_link: true. Lihat Mengganti Payment Link yang Tertunda. - Untuk mencoba lagi setelah pembayaran ditolak, panggil kembali
change-planuntuk mendapatkan link baru. - Jika link tidak pernah dibayar, link berhenti berfungsi setelah
expires_on— langganan secara otomatis menjadi bebas untuk menerima request perubahan paket baru tidak lama setelahnya. - Jika perubahan terjadwal sudah ada dan Anda menggantinya dengan
cancel_scheduled_change_plan: true, jadwal asli tetap berlaku saat link belum dibayar dan baru dibatalkan setelah link dibayar — dalam transaksi yang sama saat paket baru diterapkan.
Mengalihkan Pelanggan Setelah Pembayaran
Aturreturn_url untuk mengarahkan pelanggan kembali ke situs Anda setelah mereka membayar link:
return_url dengan parameter query berikut:
return_url memerlukan collect_via_payment_link: true. Tanpanya, request gagal dengan 422.
Mengganti Payment Link yang Tertunda
Jika pelanggan meninggalkan checkout tanpa membayar, tetapkancancel_older_payment_link: true pada request change-plan berikutnya. Dodo Payments membatalkan link yang belum dibayar, dan perubahan paket baru menggantikan perubahan yang tertunda. Link yang dibatalkan tidak lagi menerima pembayaran, bahkan pada halaman checkout yang sudah terbuka.
change-plan menerbitkan invoice sendiri. Perubahan paket yang diganti dan invoicenya dibatalkan. Jika tidak ada perubahan paket yang tertunda, cancel_older_payment_link tidak berpengaruh.
Mengelola Addon
Saat mengubah paket langganan, Anda juga dapat mengubah addon:Menerapkan Kode Diskon
Terapkan satu atau beberapa kode diskon stacked saat mengubah paket langganan (maks. 20, diterapkan sesuai urutan array):- Node.js SDK
- Python SDK
- HTTP
Perilaku Diskon Saat Perubahan Paket
discount_code pada endpoint ini deprecated, tetapi masih berfungsi untuk kompatibilitas mundur — integrasi yang ada tidak perlu segera berubah. Field ini tidak dapat digabungkan dengan discount_codes dalam request yang sama. Migrasikan ke bentuk array jika sudah memungkinkan.Mode Proration
Pilih cara menagih pelanggan saat mengubah paket:prorated_immediately
- Mengkreditkan bagian yang tidak digunakan dari siklus saat ini — paket dasar, kuantitas, dan addon — secara prorata berdasarkan sisa waktu
- Kemudian menagihkan siklus penuh pada paket, kuantitas, dan addon baru. Tagihan itu sendiri tidak pernah diprorata
- Tagihan langsung bersih = (siklus baru penuh) − (fraksi tersisa × siklus lama penuh)
- Jika kredit melebihi tagihan siklus baru (umum pada downgrade), selisihnya disimpan sebagai kredit berskala langganan untuk renewal mendatang
- Jika sedang trial, tagih segera dan beralih ke paket baru sekarang
full_immediately
- Menagihkan jumlah penuh paket baru segera
- Mengabaikan waktu tersisa dari paket lama — tidak ada kredit untuk siklus saat ini
prorated_immediately dan oleh downgrade menggunakan difference_immediately berskala langganan dan berbeda dari entitlement Credit-Based Billing. Kredit tersebut otomatis diterapkan pada renewal mendatang untuk langganan yang sama dan tidak dapat dipindahkan antar-langganan.difference_immediately
- Upgrade: segera menagihkan selisih harga antara paket lama dan baru
- Downgrade: menambahkan nilai tersisa sebagai kredit internal ke langganan dan menerapkannya otomatis pada renewal
do_not_bill
- Tidak ada tagihan atau kredit yang dihitung
- Pelanggan segera beralih ke paket baru tanpa penyesuaian penagihan
- Siklus penagihan tetap tidak berubah
- Cocok untuk migrasi sebagai bentuk layanan, perpindahan ke paket gratis, atau menyerap selisih biaya
Skenario Contoh
Gunakan angka kanonis berikut secara konsisten:- Paket saat ini: Basic seharga $30/bulan
- Target upgrade: Pro seharga $80/bulan
- Target downgrade (dari Pro): Starter seharga $20/bulan
- Siklus penagihan: 30 hari, dimulai pada 1 Januari
- Perubahan paket terjadi pada 16 Januari (tersisa 15 hari, 15 hari telah digunakan)
Upgrade: Basic ($30) → Pro ($80) with prorated_immediately
Upgrade: Basic ($30) → Pro ($80) with prorated_immediately
Downgrade: Pro ($80) → Starter ($20) with prorated_immediately
Downgrade: Pro ($80) → Starter ($20) with prorated_immediately
Upgrade: Basic ($30) → Pro ($80) with difference_immediately
Upgrade: Basic ($30) → Pro ($80) with difference_immediately
Downgrade: Pro ($80) → Starter ($20) with difference_immediately
Downgrade: Pro ($80) → Starter ($20) with difference_immediately
Upgrade: Basic ($30) → Pro ($80) with full_immediately
Upgrade: Basic ($30) → Pro ($80) with full_immediately
Mid-cycle upgrade with add-ons using prorated_immediately
Mid-cycle upgrade with add-ons using prorated_immediately
Cara Setiap Mode Memproses Penagihan
Menangani Kegagalan Pembayaran
Kontrol apa yang terjadi saat pembayaran perubahan paket gagal menggunakan parameteron_payment_failure.
Mode Kegagalan Pembayaran
- prevent_change (Recommended for critical upgrades)
- apply_change (Default)
- Perubahan paket ditandai sebagai “pending”
- Pelanggan tetap memiliki akses ke paket saat ini
- Langganan berpindah ke status
activehanya setelah pembayaran berhasil - Berguna saat Anda ingin memastikan pembayaran sebelum memberikan fitur yang ditingkatkan
on_payment_failure menggunakan pengaturan default tingkat bisnis yang dikonfigurasi di dashboard.Kapan Menggunakan Setiap Mode
Default Bisnis & Collection
Atur perilaku default upgrade dan downgrade di tingkat bisnis melalui Settings → Subscriptions. Default ini berlaku untuk semua perubahan paket melalui customer portal dan dapat ditimpa per product collection. Default terpisah tersedia untuk upgrade dan downgrade:Urutan Resolusi
Untuk perubahan paket apa pun, setiap pengaturan ditentukan dalam urutan berikut:Menangani Webhook
Lacak status langganan melalui webhook untuk mengonfirmasi perubahan paket dan pembayaran.Jenis Event yang Ditangani
subscription.active: langganan diaktifkansubscription.plan_changed: paket langganan berubah (upgrade/downgrade/perubahan addon)subscription.on_hold: tagihan gagal, renewal dihentikansubscription.renewed: renewal berhasilpayment.succeeded: pembayaran untuk perubahan paket atau renewal berhasilpayment.failed: pembayaran gagal
Memverifikasi Signature dan Menangani Intent
- Next.js Route Handler
- Express.js
Praktik Terbaik
Strategi Perubahan Paket
- Uji secara menyeluruh: Selalu uji perubahan paket dalam test mode sebelum production
- Pilih proration dengan cermat: Pilih mode proration yang sesuai dengan model bisnis Anda
- Tangani kegagalan dengan baik: Terapkan penanganan error dan logika percobaan ulang yang tepat
- Pantau tingkat keberhasilan: Lacak tingkat keberhasilan/kegagalan perubahan paket dan selidiki masalah
Implementasi Webhook
- Verifikasi signature: Selalu validasi signature webhook untuk memastikan keasliannya
- Terapkan idempotensi: Tangani event webhook duplikat dengan baik
- Proses secara asynchronous: Jangan memblokir response webhook dengan operasi berat
- Catat semuanya: Simpan log terperinci untuk debugging dan keperluan audit
User Experience
- Berkomunikasi dengan jelas: Informasikan pelanggan tentang perubahan dan waktu penagihan
- Berikan konfirmasi: Kirim konfirmasi email untuk perubahan paket yang berhasil
- Tangani kasus khusus: Pertimbangkan periode trial, proration, dan pembayaran yang gagal
- Perbarui UI segera: Tampilkan perubahan paket di interface aplikasi Anda
Masalah Umum dan Solusi
Atasi masalah umum yang ditemukan selama perubahan paket langganan:Charge created but subscription not updated
Charge created but subscription not updated
- Pemrosesan webhook gagal atau tertunda
- State aplikasi tidak diperbarui setelah menerima webhook
- Masalah transaksi database saat memperbarui state
- Terapkan penanganan webhook dengan logika percobaan ulang
- Gunakan operasi idempoten untuk pembaruan state
- Tambahkan monitoring untuk mendeteksi dan memberi alert atas event webhook yang terlewat
- Verifikasi endpoint webhook dapat diakses dan merespons dengan benar
Credits not applied after downgrade
Credits not applied after downgrade
- Ekspektasi mode proration: downgrade mengkreditkan seluruh selisih harga paket dengan
difference_immediately, sedangkanprorated_immediatelymengkreditkan waktu yang tidak digunakan pada siklus lama lalu menagihkan satu siklus penuh pada paket baru — sehingga saldo kredit hanya tersisa jika kredit tersebut melebihi harga paket baru - Kredit bersifat spesifik untuk langganan dan tidak dapat dipindahkan antar-langganan
- Saldo kredit tidak terlihat di dashboard pelanggan
- Gunakan
difference_immediatelyuntuk downgrade saat Anda menginginkan kredit otomatis - Jelaskan kepada pelanggan bahwa kredit berlaku untuk renewal mendatang pada langganan yang sama
- Implementasikan customer portal untuk menampilkan saldo kredit
- Periksa preview invoice berikutnya untuk melihat kredit yang diterapkan
Webhook signature verification fails
Webhook signature verification fails
- Webhook secret key salah
- Raw request body diubah sebelum verifikasi signature
- Algoritma verifikasi signature salah
- Verifikasi bahwa Anda menggunakan
DODO_PAYMENTS_WEBHOOK_KEYyang benar dari dashboard - Baca raw request body sebelum middleware parsing JSON apa pun
- Gunakan library verifikasi webhook standar untuk platform Anda
- Uji verifikasi signature webhook di environment development
Plan change fails with 422 error
Plan change fails with 422 error
- ID langganan atau ID produk tidak valid
- Langganan tidak dalam status aktif
- Parameter wajib tidak ada
- Produk tidak tersedia untuk perubahan paket
- Verifikasi langganan ada dan aktif
- Periksa ID produk valid dan tersedia
- Pastikan semua parameter wajib diberikan
- Tinjau dokumentasi API untuk persyaratan parameter
Immediate charge fails during plan change
Immediate charge fails during plan change
- Dana tidak mencukupi pada metode pembayaran pelanggan
- Metode pembayaran kedaluwarsa atau tidak valid
- Bank menolak transaksi
- Deteksi fraud memblokir tagihan
- Tangani event webhook
payment.faileddengan tepat - Beri tahu pelanggan untuk memperbarui metode pembayaran
- Terapkan logika percobaan ulang untuk kegagalan sementara
- Pertimbangkan untuk mengizinkan perubahan paket dengan tagihan langsung yang gagal
Subscription on hold after plan change
Subscription on hold after plan change
on_holdYang terjadi:
Saat tagihan perubahan paket gagal, langganan otomatis ditempatkan dalam status on_hold. Langganan tidak akan diperbarui secara otomatis hingga metode pembayaran diperbarui.Solusi: Perbarui metode pembayaran untuk mengaktifkan kembali langgananUntuk mengaktifkan kembali langganan dari status on_hold setelah perubahan paket gagal:- Perbarui metode pembayaran menggunakan Update Payment Method API
- Pembuatan tagihan otomatis: API otomatis membuat tagihan untuk iuran yang tersisa
- Pembuatan invoice: Invoice dibuat untuk tagihan tersebut
- Pemrosesan pembayaran: Pembayaran diproses menggunakan metode pembayaran baru
- Reaktivasi: Setelah pembayaran berhasil, langganan diaktifkan kembali ke status
active
subscription.on_hold: Langganan ditangguhkan (diterima saat tagihan perubahan paket gagal)payment.succeeded: Pembayaran iuran tersisa berhasil (setelah metode pembayaran diperbarui)subscription.active: Langganan diaktifkan kembali setelah pembayaran berhasil
- Beri tahu pelanggan segera saat tagihan perubahan paket gagal
- Berikan instruksi yang jelas tentang cara memperbarui metode pembayaran
- Pantau event webhook untuk melacak status reaktivasi
- Pertimbangkan untuk menerapkan logika percobaan ulang otomatis untuk kegagalan pembayaran sementara
Update Payment Method API Reference
Menguji Implementasi Anda
Uji implementasi perubahan paket langganan Anda secara menyeluruh:Set up test environment
- Gunakan API key test dan produk test
- Buat langganan test dengan berbagai jenis paket
- Konfigurasikan endpoint webhook test
- Siapkan monitoring dan logging
Test different proration modes
- Uji
prorated_immediatelydengan berbagai posisi dalam siklus penagihan - Uji
difference_immediatelyuntuk upgrade dan downgrade - Uji
full_immediatelyuntuk mengatur ulang siklus penagihan - Uji
do_not_billuntuk perpindahan paket tanpa tagihan/kredit - Verifikasi penghitungan kredit sudah benar
Test webhook handling
- Verifikasi semua event webhook yang relevan diterima
- Uji verifikasi signature webhook
- Tangani event webhook duplikat dengan baik
- Uji skenario kegagalan pemrosesan webhook
Test error scenarios
- Uji dengan ID langganan yang tidak valid
- Uji dengan metode pembayaran yang kedaluwarsa
- Uji kegagalan jaringan dan timeout
- Uji dengan dana yang tidak mencukupi
Monitor in production
- Siapkan alert untuk perubahan paket yang gagal
- Pantau waktu pemrosesan webhook
- Lacak tingkat keberhasilan perubahan paket
- Tinjau tiket dukungan pelanggan terkait masalah perubahan paket
Penanganan Error
Tangani error API umum dengan baik dalam implementasi Anda:HTTP Status Codes
200 OK
200 OK
ChangePlanResponse dengan payment_id, payment_link, client_secret, dan expires_on. Keempatnya nullable, sehingga body diserialisasikan sebagai {} untuk perubahan off-session biasa; semuanya terisi untuk request collect_via_payment_link yang berhasil, yang mengembalikan handle checkout — lihat Mengumpulkan Pembayaran melalui Checkout Link. Jika on_payment_failure=prevent_change, perubahan paket tetap tertunda hingga pembayaran berhasil.400 Bad Request
400 Bad Request
409 Conflict
409 Conflict
PendingPlanChangeExists). Untuk perubahan terjadwal, batalkan dengan DELETE /subscriptions/{subscription_id}/change-plan/scheduled sebelum mengirimkan perubahan baru. Untuk perubahan payment-link yang tertunda, kirim request baru dengan cancel_older_payment_link: true untuk menggantinya. Lihat Mengganti Payment Link yang Tertunda.Dengan cancel_older_payment_link: true, 409 berarti pelanggan sedang membayar link sebelumnya (PLAN_CHANGE_PAYMENT_IN_PROGRESS) atau sudah membayarnya (PLAN_CHANGE_PAYMENT_ALREADY_COMPLETED).422 Unprocessable Entity
422 Unprocessable Entity
collect_via_payment_link — bisnis tidak mengaktifkan capability tersebut, effective_at bukan immediately, atau on_payment_failure bukan prevent_change. Lihat Persyaratan. ID langganan yang tidak ada atau bukan milik akun Anda mengembalikan 404 dengan code NOT_FOUND.500 Internal Server Error
500 Internal Server Error
Format Error Response
Error mengembalikan body JSON dengancode dan message yang dapat dibaca manusia:
Langkah Berikutnya
- Tinjau Change Plan API
- Jelajahi Credit-Based Billing
- Implementasikan alert untuk
subscription.on_hold - Lihat Webhook Integration Guide