Prerequisites
Before you start, you need:- A Dodo Payments merchant account
- An API key from Developer → API Keys in the dashboard, stored in
DODO_PAYMENTS_API_KEY - A webhook secret from Developer → Webhooks, stored in
DODO_PAYMENTS_WEBHOOK_KEY - At least one subscription product created under Products
API Integration
Checkout Sessions
Create a subscription by building a checkout session with your subscription product. The customer authorizes a payment method and the subscription activates when they complete checkout.- Node.js SDK
- Python SDK
- REST API
API Response
The response includes acheckout_url:
Webhooks
Webhooks notify your server when subscription events occur. Set up your endpoint under Developer → Webhooks in the dashboard. To set up your webhook endpoint, see Webhooks.Subscription Event Types
Track these events to manage the subscription lifecycle:subscription.active— Subscription is activatedsubscription.updated— A field on the subscription changedsubscription.on_hold— A renewal or plan-change charge failedsubscription.failed— Subscription creation failed (terminal; customer must resubscribe)subscription.renewed— A recurring charge succeededsubscription.past_due— A renewal failed and the grace period started; the customer keeps access untilpast_due_ends_atsubscription.plan_changed— The plan was upgraded, downgraded, or changedsubscription.cancelled— The subscription was cancelledsubscription.expired— The subscription reached the end of its term
paused, unpaused, and update_payment_method, see Subscription Webhooks.
Payment Scenarios
Successful Payment Flow The webhook sequence depends on whether the subscription has a trial. Immediate billing (0 trial days):subscription.active: the mandate is authorized and the subscription is activated.payment.succeeded: confirms the first charge. Expect this within 2–10 minutes of checkout.
- At trial start (checkout):
subscription.activefires once the payment method is authorized. No recurring charge is taken yet. The first real charge is deferred until the trial ends. - At trial end: the recurring amount is charged, and you receive
payment.succeededtogether withsubscription.renewed.
subscription.renewed: fires on each billing cycle when the renewal payment is deducted, always alongsidepayment.succeeded. It also carries the updatednext_billing_date.
Whenever money is actually deducted for a subscription product, you get
subscription.renewed and payment.succeeded. Use subscription.renewed (rather than payment.succeeded alone) as your signal to extend access for the next cycle.- Subscription Failure
subscription.failed- Subscription creation failed due to failure to create a mandate.payment.failed- Indicates failed payment.
- Subscription On Hold
subscription.on_hold- Subscription is put on hold due to failed renewal payment or failed plan change charge. If your business has a grace period, a failed renewal first moves the subscription topast_due(subscription.past_due), and it moves toon_hold(orcancelled, depending on your grace period settings) only when the grace period ends. See Subscription States.- When a subscription goes on hold, it will not renew automatically until the payment method is updated.
Best Practice: To simplify implementation, we recommend primarily tracking subscription events for managing the subscription lifecycle.
subscription.failed vs. subscription.on_hold
These two events are easy to confuse, but they require very different handling:
Handling Subscription On Hold
When a subscription enterson_hold state, you need to update the payment method to reactivate it. This section explains when subscriptions go on hold and how to handle them.
When Subscriptions Go On Hold
A subscription is placed on hold when:- Renewal payment fails: The automatic renewal charge fails due to insufficient funds, expired card, or bank decline
- Plan change charge fails: An immediate charge during plan upgrade/downgrade fails
- Payment method authorization fails: The payment method cannot be authorized for recurring charges
Reactivating Subscriptions from On Hold
To reactivate a subscription fromon_hold state, use the Update Payment Method API. This automatically:
- Creates a charge for remaining dues
- Generates an invoice for the charge
- Processes the payment using the new payment method
- Reactivates the subscription to
activestate upon successful payment
1
Handle subscription.on_hold webhook
When you receive a
subscription.on_hold webhook, update your application state and notify the customer:2
Update payment method
When the customer is ready to update their payment method, call the Update Payment Method API:
You can also use an existing payment method ID if the customer has saved payment methods:
3
Monitor webhook events
After updating the payment method, monitor for these webhook events:
payment.succeeded- The charge for remaining dues was successfulsubscription.active- The subscription has been reactivated
Sample Subscription Event Payload
Changing Subscription Plans
You can upgrade or downgrade a subscription plan using the change plan API endpoint. This allows you to modify the subscription’s product, quantity, and handle proration.Change Plan API Reference
For detailed information about changing subscription plans, please refer to our Change Plan API documentation.
Proration Options
When changing subscription plans, you have four options for handling the immediate charge:1. prorated_immediately
- Credits the unused portion of the current billing cycle, prorated by the time remaining. The credit covers the base plan, quantity, and any add-ons
- Then charges a full cycle at the new plan, quantity, and add-ons. The charge itself is never prorated
- Net immediate charge = (full new cycle) minus (remaining fraction x full old cycle). If the credit is larger, the difference is held as subscription-scoped credit for future renewals
- During a trial period, this will immediately switch the user to the new plan, charging the customer right away
2. full_immediately
- Charges the customer the full subscription amount for the new plan with no credit for the previous cycle
- On upgrade or downgrade alike, the customer pays the entire new plan price from scratch
- Useful when you want to charge the full amount regardless of how much time was left on the old plan
3. difference_immediately
- The customer pays only the gap between the old plan price and the new plan price
- The amount does not depend on when in the cycle the change is made. The same upgrade costs the same on day 1 and on day 29
- When upgrading, the customer is immediately charged the difference. For example, $30/month → $80/month = $50 charged instantly
- When downgrading, the price difference is stored as subscription-scoped credit and applied automatically to future renewals. For example, $50/month → $20/month = $30 stored as credit
4. do_not_bill
- Applies the plan change immediately but does not charge anything at the time of the change. The new plan, quantity, and add-ons are usable straight away
- Because nothing is charged now, an upgrade gives the customer the higher plan free for the remainder of the current cycle. A downgrade takes effect immediately with no credit for the unused portion of the cycle they have already paid for
- Add-ons granted through
do_not_billare not credited on a later plan change, because they were never billed. A subsequent change bills the new add-on quantity in full - The updated plan (and quantity/add-ons) is billed at the next scheduled renewal, and the original billing date is preserved
Behavior
- When you invoke this API, Dodo Payments immediately initiates a charge based on your selected proration option
- With
prorated_immediately, a credit for the unused portion of the current cycle is calculated on every change, upgrade or downgrade alike. If that credit exceeds the new cycle charge, the remainder is added to the subscription’s credit balance. These credits are specific to that subscription and will only be used to offset future recurring payments of the same subscription - With
difference_immediately, the net is always the exact price difference. For downgrades, the excess is stored as subscription-scoped credit, the same asprorated_immediately - The
full_immediatelyoption bypasses credit calculations and charges the complete new plan amount - The
do_not_billoption applies the change immediately but defers billing to the next renewal date, which is preserved
Charge Processing
- The immediate charge initiated upon plan change usually completes processing in less than 2 minutes
- If this immediate charge fails for any reason, the subscription is automatically placed on hold until the issue is resolved
On-Demand Subscriptions
On-demand subscriptions let you charge customers flexibly, not just on a fixed schedule. This feature is available for all accounts.
subscription_data.on_demand field in your request body. This allows you to authorize a payment method without an immediate charge, or set a custom initial price.
To charge an on-demand subscription:
For subsequent charges, use the POST /subscriptions//charge endpoint and specify the amount to charge the customer for that transaction.
For a complete, step-by-step guide (including request/response examples, safe retry policies, and webhook handling), see the On-Demand Subscriptions Guide.
Key Things to Know About Subscription Billing
Trials take a $0 authorization, not a charge. When a subscription has a trial, the trial start creates a $0 mandate authorization to save the card; the first real charge happens when the trial ends. In the payments list, a subscription in a free trial shows exactly one payment with
total_amount of 0. A paid trial charges its trial_amount upfront instead.Subscription lifecycle:
past_due = a renewal failed and the grace period is running (the customer keeps access). on_hold = a renewal failed (recoverable: prompt the customer to update their payment method; dunning retries apply). expired = the term ended without renewal and cannot be reactivated. The customer must resubscribe. cancelled = ended by the customer or merchant. Most renewal failures are issuer-side declines (insufficient funds, card declined), not a Dodo error.Related API Reference
Create Subscription (Deprecated)
Legacy API for creating a subscription directly. Use Checkout Sessions for new integrations
Change Subscription Plan
API reference for upgrading, downgrading, or changing subscription plans with proration options
Update Payment Method
API reference for updating payment methods and reactivating on-hold subscriptions
Patch Subscription
API reference for updating subscription details and configuration