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

# Use Stripe Coupons and Promo Codes

> How to implement and apply Stripe coupons and promo codes in your Embeddable

Stripe offers two ways to provide discounts to your customers: Coupons and Promo Codes. While they're related, they serve different purposes and are implemented differently.

## Understanding Coupons vs Promo Codes

### Coupons

* Coupons are the underlying discount rules you create in Stripe.
* They define the actual discount (e.g., 20% off, \$10 off, etc).
* They are not customer-facing and are identified by IDs in Stripe, that can either look like `A1b2C3d4` or an ID chosen by you.
* You can create coupons in your [Stripe Dashboard](https://dashboard.stripe.com/coupons).

### Promo Codes

* Promo codes are customer-facing codes that are linked to coupons.
* They are what customers actually enter to get a discount.
* They have a customer-friendly format (e.g., "BLACKFRIDAY50"), and they also have a unique ID generated by Stripe that looks like `promo_1A2B3C4D5E6F7G8H9I0J`.
* You can create promo codes [in your Stripe Dashboard from within a Coupon](https://dashboard.stripe.com/promotion_codes).

<Note>
  Both coupons and promo codes are environment-specific - they exist either in test mode or live mode in Stripe, but not both.

  Make sure you're using the correct mode for your Embeddable. If you want to test coupons or promo codes in both modes, you'll need to create equivalent coupons and promo codes in both modes.
</Note>

## Implementing Promo Codes in Your Embeddable

There are two ways to implement promo codes in your Embeddable:

### 1. Manual Entry by Customer

To let customers enter their own promo codes:

<Steps>
  <Step title="Add Input and Button Components">
    * Add a Container component to house your promo code components.
    * Add a 2nd Container component to display the input and button components side-by-side.
    * Add an Input Box component for use to enter the promo code, with a key such as `new_promo_code`.
    * Add a Button component for the user to click to submit the code.
    * Add 2 Plain Text components to display success + error messages, giving them the content of `{{promo_code_success_message}}` and `{{promo_code_error_message}}` respectively.
  </Step>

  <Step title="Style the components">
    * Style the inner Container to use Flex to display the input and button components side-by-side, and consider giving it a max-width.
    * Style the input box to be a varying width, based on the width of the container.
    * Style the success message to be green, and the error message to be red.
  </Step>

  <Step title="Create an Action">
    Create an Action that will be triggered when the button is clicked:

    ```javascript theme={null}
    function output(userData, { setUserData }) {
      // Get the promo code from the input, using its key
      const promoCode = userData.new_promo_code;
      
      // Apply the promo code using the Stripe Checkout function
      window.StripeCheckout.applyPromotionCode(promoCode)
        .then((result) => {
          if (result.type === 'success') {
            // On success:
            // - Update the success message to show the applied discount
            // - Clear any error message
            // - Reset the input box to empty
            setUserData({
              promo_code_success_message: `Promo code "${promoCode}" applied successfully!`,
              promo_code_error_message: "",
              new_promo_code: "",
            });
          } else {
            // Handle error case
            setUserData({
              promo_code_success_message: "",
              promo_code_error_message: result.error.message || "Invalid promo code",
            });
          }
        })
        .catch((error) => {
          // Handle any unexpected errors
          setUserData({
            promo_code_success_message: "",
            promo_code_error_message: "An unexpected error occurred",
          });
        });
    }
    ```
  </Step>

  <Step title="Register User Data Keys">
    * In your Embeddable settings, add the following keys to the "Registered Keys" section:
      * `promo_code_success_message`
      * `promo_code_error_message`
    * This ensures these keys are properly tracked and managed by the Embeddables reactive engine.
  </Step>

  <Step title="Add a Trigger to the Action">
    * Add a Trigger to the Action that fires when the button is clicked.
  </Step>

  <Step title="Recommended: Reset Messages on Page Load">
    Since the Stripe checkout session is refreshed when the user refreshes or changes pages, you'll want to reset the success and error messages when the page loads, to avoid the user thinking that their promo code is still applied.

    * Create a new Action to reset the success and error messages when the page loads.

    ```javascript theme={null}
    function output(userData, { setUserData }) {
      setUserData({
        promo_code_success_message: "",
        promo_code_error_message: "",
      });
    }
    ```

    * Add a Trigger to this Action that fires on page load.
    * This ensures the messages are cleared when the Stripe checkout session is refreshed.
  </Step>
</Steps>

### 2. Automatic Application

Use this method to automatically apply a promo code for all customers.

<Note>
  A UI for handling this without editing the JSON is coming soon!
</Note>

In your Stripe component Options, open the JSON editor and add the following to the checkout session configuration:

```json theme={null}
{
  "checkout_session": {
    // ... other checkout session configuration ...
    "discounts": [  // Stripe currently only supports one object in the array
      {
        "promotion_code": "YOUR_PROMO_CODE_ID", // EITHER THIS
        "coupon": "YOUR_COUPON_ID"              // OR THIS
      }
    ]
  }
}
```

Tips:

* Replace `YOUR_PROMO_CODE_ID` or `YOUR_COUPON_ID` with your actual promo code ID from Stripe.
* Or, if you prefer, replace them with `{{promo_code_id}}` or `{{coupon_id}}` to use an ID calculated from a Computed Field or Action.
* Make sure to remove either the `promotion_code` or `coupon` key, not both.
* Make sure to remove all the comments (`// ...`) since JSON doesn't support comments.
* Make sure to remove the `// ... other checkout session configuration ...` line, since you're only adding the discounts section.

<Warning>
  When using automatic application, make sure you're using the correct promo code for your environment (test vs live mode).
</Warning>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Error: Invalid promo code">
    This usually means one of the following:

    * The promo code doesn't exist in your Stripe account.
    * You're using a test mode promo code in live mode (or vice versa).
    * The promo code has expired or been deactivated.
    * The promo code doesn't apply to the current products in the cart.
    * You're using the wrong type of value, out of the 3 options (promo code ID, coupon ID, or customer-facing promo code) - [read about the differences above](#understanding-coupons-vs-promo-codes).
  </Accordion>

  <Accordion title="Error: Promo code already applied">
    This means the customer has already applied a promo code to their checkout session. Only one promo code can be applied at a time.
  </Accordion>

  <Accordion title="Error: Coupon ID instead of Promo Code">
    If you're getting errors when trying to apply a discount, make sure you're using a promo code (customer-facing code) and not a coupon ID. The `applyPromotionCode` function expects a promo code, not a coupon ID.
  </Accordion>
</AccordionGroup>

## Using coupons with multiple Stripe Checkout components on the same page

If you have more than one Stripe Checkout component on the same page, set `use_shared_stripe_session: true` on each component. Without it, each component creates its own independent Stripe Checkout session — meaning a coupon applied to one component will not be reflected on the others, and the "Pay" button totals will get out of sync.

When all components on the page share a session, applying a promo code via `window.StripeCheckout.applyPromotionCode(...)` updates the session once and every component's "Pay" button automatically reflects the discounted total.

<Warning>
  All participating Stripe Checkout components must use the same **Checkout mode** (e.g. all Payment, or all Subscription) and the same **currency**. Mismatched values will produce an error.
</Warning>

<Note>
  Session sharing is scoped to a single page. Components on different pages each create their own independent session, so `use_shared_stripe_session` has no effect across page navigations.
</Note>

See the [Sharing a Stripe session across multiple components](/features/payments/stripe/overview#share-a-single-stripe-session-across-multiple-stripe-checkout-components) section in the Stripe Payments docs for setup instructions.

## Best Practices

1. **Test Both Modes**: Always test your promo codes in both test and live modes to ensure they work as expected.

2. **Clear Messaging**: Make sure your UI clearly communicates:
   * Where to enter the promo code.
   * When a code has been successfully applied.
   * When a code is invalid and why.
   * That only one promo code can be applied at a time.

3. **Error Handling**: Implement proper error handling in your Action to provide a good user experience when:
   * The code is invalid.
   * The code has expired.
   * The code doesn't apply to the current products.
   * The code has already been applied.

4. **Security**: Remember that promo codes are public-facing. Don't include sensitive information in them, and consider implementing rate limiting if you're concerned about brute force attempts.

5. **Data Management**:
   * Register all user data keys in your Embeddable settings to ensure proper tracking and management.
   * Reset success/error messages on page load to handle Stripe checkout session refreshes.
   * Keep your user data structure clean by clearing input fields after successful code application.
