Add Coupons to Stripe Checkout OR allow_promotion_codes: true on redirectToCheckout

Viewed 1894

With the super slick updates to Stripe Checkout I've been working out how on earth I can add a coupon input to the checkout process.

I understand I can set allow_promotion_codes: true on the Session object... but having followed a Gatsby implementation I'm using the redirectToCheckout method which wont accept those parameters.

Do you know of a way to create a new Session and pass it to the redirectToCheckout method?

I've had a long look, and can't find anything online to get the job done + as silly as this will sound given my shallow understanding / the above... it feels like something I should be able to do.

2 Answers

TL;DR; You can allow coupon codes on the Stripe checkout, you do currently have to do this by creating a session via backend, but it is very easy and only requires a few lines of JS and backend code.

To achieve this it requires:

  1. JS to AJAX call to backend to get a sessionID with allow_promotion_codes: true
  2. JS to redirectToCheckout() once got a sessionID from backend

(rather than the default of just using redirectToCheckout() directly in JS.)

Here's an example with Javascript and PHP:

Front end (Javascript): (Be sure to change out 'YOUR STRIPE PRODUCT ID' and 'YOUR AJAX ENDPOINT' values, and initiate https://js.stripe.com/v3 with your Stripe key).

    // bind the button
    document.getElementById('checkout-button').addEventListener('click', function (e) {

        // stop any normal action (if a link)
        e.preventDefault();

        // retrieve a session ID
        ajax_checkoutsession('YOUR STRIPE PRODUCT ID',function (response) {

            // got errors?
            if (typeof response.checkoutSessionId == undefined){

                // could fallback to sending with redirectToCheckout directly
                // otherwise, backend error

            }

            stripe.redirectToCheckout({
                    sessionId: response.checkoutSessionId,
            })
            .then(function (result) {


                // if error
                if (result.error) {
                    
                    // If `redirectToCheckout` fails due to a browser or network
                    // error, display the localized error message to your customer.         
                    // deal with error

                }

            })
            .catch(function (err) {
                
            // deal with non-network Stripe error

            });

        },function(err){

            // deal with AJAX error
            
        });

    }


    function ajax_checkoutsession(plan,cb,errcb){

            var data = {
                'action': 'retrieve_checkout_session',
                'plan': plan
            };

            jQuery.ajax({
                  type: "POST",
                  url: 'YOUR AJAX ENDPOINT', 
                  "data": data,
                  dataType: 'json',
                  timeout: 20000,
                  success: function(response) {

                    // callback
                    if (typeof cb == "function") cb(response);

                    return response;

                  },
                  error: function(response){ 

                    // callback
                    if (typeof errcb == "function") errcb(response);

                  }

            });

    }

And then the backend php is pretty simple... (Requires the Stripe library, your Stripe secret key, and your success/cancel URLs):

// load vendor files
require(dirname( __FILE__ ) . '/vendor/autoload.php');

// setup Stripe
\Stripe\Stripe::setApiKey('YOUR STRIPE SECRET KEY');

// retrieve plan / product
$plan = 'defaultplan'; if (isset($_POST['plan'])) $plan = sanitize_text_field( $_POST['plan'] );

// build any line items (for now, simply one)
$line_items = [[
    'price' => $plan,
    'quantity' => 1
]];

// Sign customer up for subscription
// Note we could use: `client_reference_id`, `customer`, or `customer_email` for returning customers
$checkout_session = \Stripe\Checkout\Session::create([
    'success_url' => 'https://yoursite.com/success?session_id={CHECKOUT_SESSION_ID}',
    'cancel_url' => 'https://yoursite.com/cancelled',
    'payment_method_types' => ['card'],
    'mode' => 'subscription',
    'allow_promotion_codes' => true,
    'line_items' => $line_items
]);

echo json_encode(['checkoutSessionId' => $checkout_session['id']]);
exit();

Caveats:

  • If for some reason your AJAX sessionID generation breaks, your checkout won't work. (You can get around this by falling back to a raw redirectToCheckout() call.
  • The above example 100% works today for Subscriptions, (will need adapting for other modes of payment)

Useful links:

Unfortunately it seems you can't use allow_promotion_codes: true with client-only Checkout - it only works with the server-side implementation.

Related