Implementing Coupon/Promocode discount in Stripe, Laravel, Cashier
Tags: laravel, php, stripe
Published: 2021-05-25 05:15:14

I implemented a discount feature in my service this week, but I didn't find much information on how to implement it in the tech forums, so I'm sharing it here. 

# Environment

- Laravel 6 LTS
- Cashier 12
- Stripe SDK 7.70 depends from Cashier

# What does it mean to give a "discount" in Stripe?

There are two main ways to offer price promotions to users on Stripe: Trial and Coupon. Trial offers a free trial for the first N days of the contract, while Coupon offers a discount of N dollars or N %. 

I referred to this issue comments, but although it mentions Coupons, there was no explanation about Promotion Codes. Therefore, this article will explain about Promotion Code.

https://github.com/laravel/cashier-stripe/issues/167

# What is Promotion Code ?

Promotion codes are human readable codes that can be issued in multiples of one Coupon. Both can be applied when creating a subscription, but where the Coupon defaults to a random ID, the Promotion code can be given any name (such as DEVTO90OFF).

Although the discount conditions are determined by the Coupon object, Promocode allows you to set the number of coupons available and their duration arbitrarily (within the limits of the Coupon itself), so the following configuration is possible

- Coupon 90% off until 01/31/2022 Unlimited number of uses
  - **DEVTO90** Until 01/31/2022 (Coupon value will be set if empty) Unlimited number of uses
  - **SUMMER90** Until 2021/08/31 Limit of 10 copies

In this way, it is possible to add "color" to the coupon by determining the location and conditions of distribution. For example, "Twitter only! 50% off coupon for 7 days only! and so on.

Then, let's implement it.

# Issue a coupon on Stripe console

You can issue a coupon from this URL.

https://dashboard.stripe.com/test/coupons

At the bottom of the screen where you enter the coupon conditions, there is a switch that says "Use customer-facing coupon codes". This is the promotion code.

You can also add a Promotion code to a coupon you have already issued. Just open the coupon detail page and click "Add a promotion code".

You can give the Promotion code any name you like. It should have an exciting name, preferably with a number so that customers can expect a discount.

# Create a method to check if Promocode is valid.

In Laravel/Cashier, when you create a subscription, you can apply a promo code by simply adding the method `withPromotionCode($code)` . 
But you need to be careful here. The argument $code is not "FRIENDS20" for humans, but an API ID starting with "promo_".

I don't want to manage this synchronously between Stripe and my own application, and if possible, it would be helpful to be able to check if Promocode is valid.

So, I created the following method to check if the promo code exists, and if so, to return the API-ID.

```
private function validatePromocode($code)
{
    try {
        $promoCodes = Cache::remember('stripe-cache-promocodes', 600, function () {
            \Stripe\Stripe::setApiKey(YOUR_STRIPE_API_SECRET);
            return \Stripe\PromotionCode::all(["active"=>true]);
        });
        foreach ($promoCodes->data as $promoCode) {
            if ($code==$promoCode->code) {
                // valid
                return $promoCode->id;
            }
        }
        return false;
    } catch (\Exception $e) {
        return false;
    }
}
```

This method retrieves all valid, unexpired Promocodes (cached for 10 minutes) and returns the ID for Stripe if the human code matches.

# Create a subscription with Promotion code

You can then create a subscription based on the ID that comes back.

```
$user->newSubscription('default', STRIPE_PRICE_API_ID )
        ->withPromotionCode($promoCodeId)
        ->create();
```
# How to notify the user of the result of the promotion being applied

Since I couldn't to spend much time, I decided to have them visit the Customer Portal that Stripe provides during the trial period. 

In the Customer Portal, they can see that they are scheduled to be charged at a discounted price after the actual trial is over, which is a relief.

If you want to be even more helpful, you can create the validate API to check the Promocode that I mentioned earlier on the subscription application page.