> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dodopayments.com/llms.txt
> Use this file to discover all available pages before exploring further.

# v1.99.0 (May 25, 2026)

> Stacked discount codes (up to 20 per checkout, payment, or subscription), seven new customer notification emails for refunds and subscription lifecycle events, Sunbit BNPL for US customers, checkout payment page overhaul lifting success rates by 2–3%, product form rework with live preview and autosave, and Business Settings redesign

## New Features

### 1. **Stacked Discount Codes**

Checkout sessions, payments, subscriptions, and plan changes now accept **up to 20 discount codes in a single request** via the `discount_codes` array. Codes are applied **in array order** — the first eligible code reduces the base price, the second reduces the already-discounted price, and so on — so you can layer campaigns without creating bespoke combined codes.

<Frame>
  <img src="https://mintcdn.com/dodopayments/Ehnri26kKx69Tfxe/images/changelog/v1.99.0/stacked-discounts.png?fit=max&auto=format&n=Ehnri26kKx69Tfxe&q=85&s=7a2606d7027de6e662cf9be6b7df8213" alt="Confirm Plan Change dialog with multiple stacked discount codes" style={{ maxHeight: '500px', width: 'auto' }} width="1132" height="1023" data-path="images/changelog/v1.99.0/stacked-discounts.png" />
</Frame>

```typescript theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [{ product_id: 'prod_abc', quantity: 1 }],
  discount_codes: ['WELCOME10', 'BLACKFRIDAY20'], // applied in this order
  customer: { email: 'user@example.com' },
  return_url: 'https://yoursite.com/return'
});
```

**Where it applies**

| Surface           | Field            | Max codes |
| ----------------- | ---------------- | --------- |
| Checkout Sessions | `discount_codes` | 20        |
| Payments          | `discount_codes` | 20        |
| Subscriptions     | `discount_codes` | 20        |
| Plan Changes      | `discount_codes` | 20        |

**Plan change behavior**

| `discount_codes` value      | Effect                                                                                           |
| --------------------------- | ------------------------------------------------------------------------------------------------ |
| Not provided                | Existing discounts with `preserve_on_plan_change=true` are kept if applicable to the new product |
| `[]` (empty array)          | All existing discounts are removed from the subscription                                         |
| `['CODE_A', 'CODE_B', ...]` | Replaces any existing discounts with this stacked set, applied in array order                    |

**Response shape**

The full set of applied discounts is returned under the `discounts` array on payments and subscriptions — each entry includes `discount_id`, `position`, and `cycles_remaining` (for subscriptions). The legacy singular `discount_id` field is deprecated but still present for backward compatibility.

<Info>
  The singular `discount_code` field is **deprecated** but still fully supported — existing integrations continue to work without changes. It cannot be combined with `discount_codes` in the same request. We recommend migrating to `discount_codes` when convenient, even for single codes, to take advantage of stacking and the richer response shape.
</Info>

Learn more: [Discount Codes](/features/discount-codes) | [Checkout Session](/developer-resources/checkout-session) | [Plan Changes](/developer-resources/subscription-upgrade-downgrade)

### 2. **Seven New Customer Notification Emails**

Seven new transactional emails are now sent to your customers automatically, covering refund confirmations, subscription lifecycle milestones, and payment failures. Each email is independently toggleable from **Settings → Communication** under the **Customer Emails** section.

<Frame>
  <img src="https://mintcdn.com/dodopayments/Ehnri26kKx69Tfxe/images/changelog/v1.99.0/customer-notification-emails.png?fit=max&auto=format&n=Ehnri26kKx69Tfxe&q=85&s=44cad42723269d9728a9dae2a061613b" alt="Customer Emails settings panel with toggles for each notification email" style={{ maxHeight: '500px', width: 'auto' }} width="1694" height="1020" data-path="images/changelog/v1.99.0/customer-notification-emails.png" />
</Frame>

**Opt-in (enabled by default)**

| Email                                               | When it fires                                                                      |
| --------------------------------------------------- | ---------------------------------------------------------------------------------- |
| **Refund Successful**                               | A refund is successfully processed and funds are on their way back to the customer |
| **Subscription Trial Ending**                       | \~2 days before a trial expires and the first billing charge occurs                |
| **Subscription Cancelled Immediately**              | A subscription is cancelled with immediate effect                                  |
| **Subscription Set to Cancel at Next Billing Date** | A subscription is scheduled to cancel at end of the current billing period         |

**Opt-out (disabled by default)**

| Email                           | When it fires                                                                                                                                  |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| **Payment Failed**              | A payment attempt fails — enable if you want Dodo Payments to notify the customer directly rather than handling it in your own system          |
| **Subscription Renewal Failed** | A subscription renewal payment fails specifically; fires instead of (not in addition to) the general Payment Failed email for renewal payments |
| **Upcoming Renewal Reminder**   | \~2 days before a subscription renews                                                                                                          |

<Tip>
  If you manage customer communication yourself via webhooks, leave the opt-out emails disabled to avoid sending customers duplicate notifications for the same event.
</Tip>

<Note>
  Customer emails are separate from the notification emails sent to your team. Disabling a customer email does not affect your team's notifications for the same event.
</Note>

Learn more: [Communication Preferences](/features/communication-preferences)

### 3. **Sunbit — Installment Financing for US Customers**

**Sunbit** is now available as a Buy Now, Pay Later payment method, letting US customers split purchases into manageable monthly installments at checkout.

| Feature            | Details                                |
| ------------------ | -------------------------------------- |
| **Availability**   | United States                          |
| **Currency**       | USD                                    |
| **Minimum amount** | \$60.00                                |
| **Maximum amount** | \$19,999.00                            |
| **Subscriptions**  | Not supported (one-time payments only) |

Pass `sunbit` in `allowed_payment_method_types` to enable it on a checkout session:

```javascript theme={null}
const session = await client.checkoutSessions.create({
  product_cart: [{ product_id: 'prod_123', quantity: 1 }],
  allowed_payment_method_types: ['sunbit', 'credit', 'debit'],
  return_url: 'https://example.com/success'
});
```

The customer completes a short financing application in the Sunbit modal at checkout; once approved, the payment confirms and you receive funds as normal.

<Tip>
  Always include `credit` and `debit` as fallbacks. Not all customers will qualify for Sunbit financing, and transactions outside the $60.00–$19,999.00 range won't display the option.
</Tip>

Learn more: [BNPL Payment Methods](/features/payment-methods/bnpl)

## Improvements

### 4. **Checkout Payment Page Overhaul**

The payment page on checkout has been substantially reworked end-to-end — tighter layout, faster perceived load, clearer validation states, and refined card-input UX. In aggregate, these changes lifted **observed checkout success rates by \~2–3%** across global traffic.

<div style={{ display: 'flex', gap: '16px', alignItems: 'flex-start', flexWrap: 'wrap' }}>
  <div style={{ flex: '1 1 280px', minWidth: '260px' }}>
    <Frame caption="Before">
      <img src="https://mintcdn.com/dodopayments/Ehnri26kKx69Tfxe/images/changelog/v1.99.0/checkout-payment-before.png?fit=max&auto=format&n=Ehnri26kKx69Tfxe&q=85&s=cd86eb287a4688e14bb01e836382744f" alt="Previous checkout payment page" width="509" height="695" data-path="images/changelog/v1.99.0/checkout-payment-before.png" />
    </Frame>
  </div>

  <div style={{ flex: '1 1 280px', minWidth: '260px' }}>
    <Frame caption="After">
      <img src="https://mintcdn.com/dodopayments/Ehnri26kKx69Tfxe/images/changelog/v1.99.0/checkout-payment-after.png?fit=max&auto=format&n=Ehnri26kKx69Tfxe&q=85&s=4eb10926ab5a1a1c97ab4cbf16e78fb2" alt="Redesigned checkout payment page" width="1114" height="1612" data-path="images/changelog/v1.99.0/checkout-payment-after.png" />
    </Frame>
  </div>
</div>

What changed:

* **Smoother field interactions** — autofocus, smarter tab order, and improved keyboard navigation on the card form
* **Cleaner error and loading states** — inline validation surfaces precisely where the customer needs to act, replacing the previous full-form error banner pattern
* **Faster paint** — skeletons and progressive hydration eliminate the brief blank-state flicker on slow networks
* **Mobile polish** — tap targets, scroll behavior, and keyboard handling tuned specifically for mobile checkout, where the majority of traffic now lives

<Tip>
  No integration changes are required. Existing checkout sessions automatically pick up the new payment page.
</Tip>

### 5. **Product Form Rework**

The product **create**, **edit**, and **duplicate** flows have been rebuilt from the ground up around a single, consistent form experience.

<Frame>
  <img src="https://mintcdn.com/dodopayments/Ehnri26kKx69Tfxe/images/changelog/v1.99.0/product-form.png?fit=max&auto=format&n=Ehnri26kKx69Tfxe&q=85&s=12693e04457400a4aa33063ef0d73221" alt="Unified product form with Basic Details, Media & Description, Pricing, and a live checkout preview side-by-side" style={{ maxHeight: '500px', width: 'auto' }} width="1143" height="959" data-path="images/changelog/v1.99.0/product-form.png" />
</Frame>

Highlights:

* **Live preview** — see how your product appears on the checkout and customer portal as you edit, side-by-side with the form
* **Autosave** — drafts are persisted automatically, so navigating away or losing your tab no longer means losing your work
* **Markdown editor** — product descriptions now support a full markdown editor with live rendering, link previews, and inline formatting controls
* **Duplicate flow parity** — duplicating a product opens the same unified form pre-filled, instead of a stripped-down dialog, so you can adjust every field before saving the copy

<Tip>
  Use **Duplicate** to spin up regional or pricing-tier variants of an existing product without re-entering descriptions, metadata, or fulfilment configuration.
</Tip>

### 6. **Business Settings Page Redesign**

The **Settings → Business** page has been redesigned to make configuration easier to scan and faster to update. Settings are now grouped into clearer sections with explanatory copy that describes the impact of every toggle before you flip it.

There are **no behavioural changes** to existing settings — only the layout, grouping, and surrounding explanations have improved.

<Frame>
  <img src="https://mintcdn.com/dodopayments/Ehnri26kKx69Tfxe/images/changelog/v1.99.0/business-settings.png?fit=max&auto=format&n=Ehnri26kKx69Tfxe&q=85&s=7603e02f67bb05a590681400f1e3f4b5" alt="Redesigned Business Settings page with grouped sections for Business Info, Brands, currency, security, and tracking" style={{ maxHeight: '500px', width: 'auto' }} width="1195" height="893" data-path="images/changelog/v1.99.0/business-settings.png" />
</Frame>

## Improvements

* **`credits_amount` override now propagated correctly to GET checkout session and payment link routes** — when a checkout session or payment link was created with a per-checkout `credit_entitlements` override, fetching that session or link via GET was returning the product-level default `credits_amount` instead of the overridden value. This is now fixed.
* **Refund action disabled for fully refunded payments** — the Refund button on a payment is now disabled once a payment is fully refunded, with a tooltip explaining why. Previously the button remained active and returned an error only after submission.
* Minor bug fixes and stability improvements across the platform
