DEV Community

Cover image for Integrate Stripe Payment Gateway with Vue 3 and Laravel
ScriptMint
ScriptMint

Posted on

Integrate Stripe Payment Gateway with Vue 3 and Laravel

This article is the second part of the payment gateway integration with Vue 3 & Laravel. This time we will discuss integrating Stripe Payment Gateway without using any external package. Stripe Payment Gateway

There are many Vue 3 components available for integrating Stripe Payment Gateway. Though I respect the open-source authors for making such components available for FREE, but I am not a big fan of external packages. I try to keep the number of external packages as low as possible because there are times when package authors don’t update their package (for any reason) or the package has any compatibility issues when you try to update your application.

Simply, if I can create the component myself, I don’t use any external package.

Hi, I am a Full Stack Developer working with Laravel, Vue.js & Tailwind CSS.

Stripe is one of the most popular Payment Gateway which allows you to collect payment worldwide via Credit Card and other payment methods.

Integrating Stripe Payment Gateway with Vue 3 & Laravel is quite simple.

To start with the integration, make sure you have an active and verified account with Stripe. Once you signup, you will need to provide some information related to your business. Stripe may take 2–3 working days to activate your account. In my case, I got a verified account in less than 4 hours.

Once your account is activated, login into the Stripe dashboard. Navigate to Developers -> API Keys and generate key/secret pair for integration.

Before going for any live transactions, you should always test your transactions in test mode. You can generate key/secret pair for the test as well as live mode.

Next, you need to add the Stripe composer package to your Laravel Project which you can do using the below command:



composer required stripe/stripe-php


Enter fullscreen mode Exit fullscreen mode

How I setup my MacBook setup for Development!

Next, We will load the Stripe JS file to process the payment securely and also to ensure that payment details are sent directly to Stripe without hitting other server.



<script src="https://js.stripe.com/v3/"></script>


Enter fullscreen mode Exit fullscreen mode

Next, we will need 3 different APIs to process the payment.

  • Payment Initiate API
  • Payment Success API
  • Payment Failure API

Let’s create these APIs in your route file.



use App\Http\Controller\StripeController;

Route::post('payment/initiate', [StripeController::class, 'initiatePayment']);
Route::post('payment/complete', [StripeController::class, 'completePayment']);
Route::post('payment/failure', [StripeController::class, 'failPayment']);


Enter fullscreen mode Exit fullscreen mode

Let’s create StripeController class with initiatePayment method.



use Stripe\StripeClient;
use Stripe\PaymentIntent;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Stripe\Stripe as StripeGateway;

public function initiatePayment(Request $request)
{
    StripeGateway::setApiKey('STRIPE_SECRET_KEY');

    try {
        $paymentIntent = PaymentIntent::create([
            'amount' => $request->amount * 100, // Multiply as & when required
            'currency' => $request->currency,
            'automatic_payment_methods' => [
                'enabled' => true,
            ],
        ]);

        // Save the $paymentIntent->id to identify this payment later
    } catch (Exception $e) {
        // throw error
    }

    return [
        'token' => (string) Str::uuid(),
        'client_secret' => $paymentIntent->client_secret
    ];
}


Enter fullscreen mode Exit fullscreen mode

Stripe processes the amount in cents for maximum currency i.e. you need to multiply the amount by 100. There are some zero decimal currencies like JPY which don’t need any multiplication.

To initiate a payment, we first need to create a Payment Intent with Stripe Payment Gateway. We will pass the amount and the currency of the payment and save this Payment Intent for future use.

This Payment Intent also generates a Client Secret which we will pass as a response.

Now, we will create a Payment.vue component as follows:



<template>
    <form id="payment-form">
        <div id="payment-element">
            <!-- Stripe will create form elements here -->
        </div>
        <button type="submit" @click="handleSubmit">Pay via Stripe</button>
    </form>
</template>

<script setup>
import { ref, onMounted } from "vue"

const token = ref(null)
const stripe = ref(null)
const elements = ref(null)

onMounted(() => {
    axios.post('INITIATE_PAYMENT_API', {
        amount: 150,
        currency: 'USD'
    }).then(response => {
        token.value = response.token // Use to identify the payment
        stripe.value = Stripe(STRIPE_PUBLISHABLE_KEY);
        const options = {
            clientSecret: response.clientSecret,
        }

        elements.value = stripe.value.elements(options);
        const paymentElement = elements.value.create('payment');
        paymentElement.mount('#payment-element');
    }).catch(error => {
        // throw error
    })
})

const handleSubmit = async (e) => {
    e.preventDefault();

    const { error } = await stripe.value.confirmPayment({
        elements: elements.value,
        redirect: "if_required"
    });

    if (error === undefined) {
        axios.post("PAYMENT_SUCCESS_API", {
            token: token.value,
        })
    } else {
        axios.post("PAYMENT_FAILURE_API", {
            token: token.value,
            code: error.code,
            description: error.message,
        })
    }
}
</script>


Enter fullscreen mode Exit fullscreen mode

We are basically creating an empty form without any input. The reason for creating an empty form is that Stripe Payment Gateway dynamically creates form input and Credit Card details are sent securely to the Stripe server only.

The mounted method of the component generates the form dynamically by using the publishable key & client secret sent by the payment initiates API.

Stripe Payment Gateway

Once you click on the “Pay via Stripe” button, the handleFunction confirms the payment with the Stripe server.

If the payment is successful i.e. there is no error with the payment, you can call the Payment Success API with the token you received during Payment Initiate API.



use Stripe\StripeClient;
use Illuminate\Http\Request;

public function completePayment(Request $request)
{
    $stripe = new StripeClient('STRIPE_SECRET_KEY');

    // Use the payment intent ID stored when initiating payment
    $paymentDetail = $stripe->paymentIntents->retrieve('PAYMENT_INTENT_ID');

    if ($paymentDetail->status != 'succeeded') {
        // throw error
    }

    // Complete the payment
}


Enter fullscreen mode Exit fullscreen mode

In case of any error, you can call Payment Failure API with the error details.



use Illuminate\Http\Request;

public function failPayment(Request $request)
{
    // Log the failed payment if you wish
}


Enter fullscreen mode Exit fullscreen mode

Creating your own component to do the job always feels good. You are basically no longer dependent on any other external package.

If you face any issues or have any query, you can write me at hello@scriptmint.com

Integrate Razorpay Payment Gateway with Vue 3 & Laravel

Top comments (4)

Collapse
 
websilvercraft profile image
websilvercraft

I also added a mechanism to be able to use multiple payment processors: Dynamic Payment Processor Selection in Laravel 11: Using the Factory Pattern

Collapse
 
giovanni_gatto profile image
Giovanni Gatto

there's a typo in the composer command, it should say require instead of required

Collapse
 
dee_veloper_23d430bee42e8 profile image
Dee Veloper

Where is the first part?

Collapse
 
t1m9m profile image
Tahsin Alam

Thank you so much for the article.