Laravel

Webhooks in Payment Gateway And Authorization

  • December 13, 2024
  • 8 min read
Webhooks in Payment Gateway And Authorization

What are Webhooks ?

A webhook is a way for one system to send real-time data to another system whenever a specific event occurs. Unlike APIs that require polling (periodically checking for updates), webhooks allow you to “subscribe” to events so the data gets sent to you immediately when the event happens. Webhooks are lightweight and efficient because they only send data when triggered.

How Does a Webhook Work?

  1. Setup: A client (your system) provides a callback URL to the server (the service you’re using). This URL is the endpoint where the server will send data when an event occurs.
  2. Trigger: An event occurs on the server, such as a new customer signing up or an order being completed.
  3. Notification: The server sends an HTTP POST request to the client’s callback URL with details of the event (usually in JSON or XML format).
  4. Processing: The client receives the request, processes the data, and responds (e.g., with a 200 OK status code to acknowledge receipt).Managing Net Off Scenarios in Payment Processing and API Responses 

    What is a Net Off Scenario in Payment Processing?

    A net off scenario occurs when a payment transaction appears successful from the user’s perspective but does not fully process or settle on the backend due to various reasons, such as:

    1. Network Issues: Connectivity problems during the payment confirmation phase.
    2. Gateway Errors: Payment gateway processes the transaction but fails to notify your server due to internal errors.
    3. Delayed Processing: Payment gets queued or delayed in the gateway or banking system.
    4. Server Timeout: Your server or the gateway server times out while awaiting a response.
    5. Webhook Failures: The webhook notification from the gateway fails to reach your server.

    In such cases, reconciliation between the user experience and the actual transaction status is crucial.

    In Laravel Use Given Code as Below For Capturing Different event of WebHook

    public function handleWebhook(Request $request)
        {
            Stripe::setApiKey(env('STRIPE_SECRET'));
    
    
    
    
            $payload = $request->getContent();
            $sig_header = $request->header('Stripe-Signature');
            $endpoint_secret = env('STRIPE_WEBHOOK_SECRET');
    
    
    
    
            try {
    
    
    
    
                $event = Webhook::constructEvent($payload, $sig_header, $endpoint_secret);
            } catch (\UnexpectedValueException $e) {
    
    
    
    
                return response()->json(['error' => 'Invalid payload'], 400);
            } catch (\Stripe\Exception\SignatureVerificationException $e) {
                // Invalid signature
                return response()->json(['error' => 'Invalid signature'], 400);
            }
    
    
    
    
            DB::beginTransaction();
    
    
    
    
            try {
                $eventData = $event->data->object;
    
    
    
    
                if ($event->type === 'payment_method.attached') {
                    $subcriptionAttachPayment = new CustomerSubscriptionPaymentAttachment();
                    $subcriptionAttachPayment->stripe_payment_method_id = $eventData->id;
                    $subcriptionAttachPayment->type = $eventData->type;
                    $subcriptionAttachPayment->customer_stripe_id = $eventData->customer;
                    $subcriptionAttachPayment->card_brand = (isset($eventData->card)) ? $eventData->card->brand : "";
                    $subcriptionAttachPayment->card_exp_month = (isset($eventData->card)) ? $eventData->card->exp_month : "";
                    $subcriptionAttachPayment->card_exp_year = (isset($eventData->card)) ? $eventData->card->exp_year : "";
                    $subcriptionAttachPayment->card_last4 = (isset($eventData->card)) ? $eventData->card->last4 : "";
                    $subcriptionAttachPayment->country = (isset($eventData->card)) ? $eventData->card->country : "";
                    $subcriptionAttachPayment->payment_created_at = Carbon::createFromTimestamp((int) $eventData->created);
                    $subcriptionAttachPayment->payment_stripe_object_detail = json_encode($event->data->object, true);
    
    
    
    
                    $subcriptionAttachPayment->save();
    
    
    
    
                }
    
    
    
    
                if ($event->type === 'customer.deleted') {
                    CustomerStripeId::where('stripe_id', $eventData->id)->delete();
    
    
    
    
                }
    
    
    
    
                if ($event->type === 'customer.subscription.created') {
                    $customerTransaction = new CustomerSubscriptionTransaction();
                    $customerTransaction->stripe_subscription_id = $eventData->id;
                    $customerTransaction->stripe_customer_id = $eventData->customer;
                    $customerTransaction->payment_method_id = $eventData->default_payment_method;
    
    
    
    
                    $customerTransaction->stripe_product_id = $eventData->plan->product;
    
    
    
    
                    $customerTransaction->amount_received = $eventData->plan->amount;
                    $customerTransaction->currency_type = $eventData->plan->currency;
                    $customerTransaction->status = $eventData->status;
                    $customerTransaction->save();
    
    
    
    
                }
    
    
    
    
                if ($event->type === 'customer.subscription.updated') {
    
    
    
    
                    $inactivePlanId = isset($event->data->previous_attributes->plan) ? $event->data->previous_attributes->plan->id : "";
                    $customer = CustomerSubscriptionTransaction::where('stripe_customer_id', $eventData->customer)->where('stripe_subscription_id', $eventData->id)->update([
                        'status' => $eventData->status,
                        'stripe_product_id' => $eventData->plan->product,
                        'active_plan_id' => $eventData->plan->id,
                        'inactive_plan_id' => $inactivePlanId,
                        'canceled_at' => Carbon::createFromTimestamp((int) ($eventData->canceled_at)) ?? "",
                        'cancellation_comment' => isset($eventData->cancellation_details) ? $eventData->cancellation_details->comment : "",
                        'cancellation_feedback' => isset($eventData->cancellation_details) ? $eventData->cancellation_details->feedback : "",
                        'subscription_start_at' => Carbon::createFromTimestamp((int) ($eventData->current_period_start)),
                        'subscription_end_at' => Carbon::createFromTimestamp((int) ($eventData->current_period_end)),
                        'billing_cycle_anchor' => Carbon::createFromTimestamp((int) ($eventData->billing_cycle_anchor)),
                        'stripe_subscription_detail_object' => json_encode($event->data->object, true)
                    ]);
    
    
    
    
                    if (isset($event->data->previous_attributes->plan)) {
                        $subscriptionCurrentPlanId = $eventData->plan->id;
    
    
    
    
                        $previousSubscriptionPlanId = $event->data->previous_attributes->plan->id;
    
    
    
    
                        if ($subscriptionCurrentPlanId !== $previousSubscriptionPlanId) {
    
    
    
    
                            $customer = CustomerSubscriptionTransaction::where('stripe_customer_id', $eventData->customer)->where('stripe_subscription_id', $eventData->id)->update([
                                'update_plan_status' => '1',
    
    
    
    
                            ]);
    
    
    
    
                        }
    
    
    
    
                    }
    
    
    
    
                }
    
    
    
    
                if ($event->type === 'customer.subscription.deleted') {
                    $customer = CustomerSubscriptionTransaction::where('stripe_customer_id', $eventData->customer)->where('stripe_subscription_id', $eventData->id)->update([
                        'status' => $eventData->status,
                        'stripe_product_id' => $eventData->plan->product
                    ]);
                }
    
    
    
    
                if ($event->type === 'payment_intent.succeeded') {
                    $subscriptionIntent = new SubscriptionPaymentIntent();
                    $subscriptionIntent->payment_intent_id = $eventData->id;
                    $subscriptionIntent->stripe_customer_id = $eventData->customer;
                    $subscriptionIntent->payment_method = $eventData->payment_method;
                    $subscriptionIntent->description = $eventData->description;
                    $subscriptionIntent->amount_send = $eventData->amount;
                    $subscriptionIntent->amount_received = $eventData->amount_received;
                    $subscriptionIntent->status = $eventData->status;
                    $subscriptionIntent->invoice = $eventData->invoice;
                    $subscriptionIntent->stripe_payment_detail_object = json_encode($event->data->object, true);
                    $subscriptionIntent->save();
    
    
    
    
                }
    
    
    
    
                if ($event->type === 'invoice.payment_succeeded') {
    
    
    
    
                    $activeProtionStatus = $eventData->lines->data[0]->proration;
    
    
    
    
                    if ($activeProtionStatus) {
                        $previousProductItemPlanId = $eventData->lines->data[0]->plan->id;
                        $previousProductPriceAmount = $eventData->lines->data[0]->amount;
                        $previousProductPriceAmountExculdingTax = $eventData->lines->data[0]->amount_excluding_tax;
                        $previousProductDiscription = $eventData->lines->data[0]->description;
                        $previousProductItemProduct = $eventData->lines->data[0]->plan->product;
    
    
    
    
                        $currentProductItemPlanId = $eventData->lines->data[1]->plan->id;
                        $currentProductItemProduct = $eventData->lines->data[1]->plan->product;
    
    
    
    
                        $currentProductProductPriceAmount = $eventData->lines->data[1]->amount;
                        $currentProductProductPriceAmountExculdingTax = $eventData->lines->data[1]->amount_excluding_tax;
                        $currentProductDiscription = $eventData->lines->data[1]->description;
    
    
    
    
                    } else {
                        $previousProductItemPlanId = "";
                        $previousProductItemProduct = "";
                        $previousProductPriceAmount = "";
                        $previousProductPriceAmountExculdingTax = "";
                        $previousProductDiscription = "";
    
    
    
    
                        $currentProductDiscription = $eventData->lines->data[0]->description;
                        $currentProductProductPriceAmount = $eventData->lines->data[0]->amount;
                        $currentProductProductPriceAmountExculdingTax = $eventData->lines->data[0]->amount_excluding_tax;
    
    
    
    
                        $currentProductItemPlanId = $eventData->lines->data[0]->plan->id;
                        $currentProductItemProduct = $eventData->lines->data[0]->plan->product;
                    }
    
    
    
    
                    $subscriptionIntentInvoice = new SubscriptionPaymentInvoice();
    
    
    
    
                    $subscriptionIntentInvoice->invoice_id = $eventData->id;
                    $subscriptionIntentInvoice->charge = $eventData->charge ?? "";
                    $subscriptionIntentInvoice->number = $eventData->number;
    
    
    
    
                    $subscriptionIntentInvoice->previous_product_description = $previousProductDiscription;
                    $subscriptionIntentInvoice->current_product_description = $currentProductDiscription;
    
    
    
    
                    $subscriptionIntentInvoice->total = $eventData->total;
                    $subscriptionIntentInvoice->total_excluding_tax = $eventData->total_excluding_tax;
    
    
    
    
                    $subscriptionIntentInvoice->subtotal = $eventData->subtotal;
                    $subscriptionIntentInvoice->subtotal_excluding_tax = $eventData->subtotal_excluding_tax;
    
    
    
    
                    $subscriptionIntentInvoice->previous_product_price_amount = $previousProductPriceAmount;
                    $subscriptionIntentInvoice->previous_product_excluding_amount = $previousProductPriceAmountExculdingTax;
    
    
    
    
                    $subscriptionIntentInvoice->current_product_price_amount = $currentProductProductPriceAmount;
                    $subscriptionIntentInvoice->current_product_excluding_tax_amount = $currentProductProductPriceAmountExculdingTax;
    
    
    
    
                    $subscriptionIntentInvoice->current_product_id = $currentProductItemProduct;
                    $subscriptionIntentInvoice->current_plan_id = $currentProductItemPlanId;
    
    
    
    
                    $subscriptionIntentInvoice->previous_product_id = $previousProductItemProduct;
                    $subscriptionIntentInvoice->previous_plan_id = $previousProductItemPlanId;
                    $subscriptionIntentInvoice->proration = $activeProtionStatus;
    
    
    
    
                    $subscriptionIntentInvoice->stripe_subscription_id = $eventData->subscription;
                    $subscriptionIntentInvoice->hosted_invoice_url = $eventData->hosted_invoice_url;
                    $subscriptionIntentInvoice->invoice_pdf = $eventData->invoice_pdf;
                    $subscriptionIntentInvoice->customer_name = $eventData->customer_name;
                    $subscriptionIntentInvoice->customer_email = $eventData->customer_email;
                    $subscriptionIntentInvoice->collection_method = $eventData->collection_method;
                    $subscriptionIntentInvoice->account_name = $eventData->account_name;
                    $subscriptionIntentInvoice->invoice_created_at = Carbon::createFromTimestamp($eventData->created);
                    $subscriptionIntentInvoice->status = $eventData->status;
    
    
    
    
                    $subscriptionIntentInvoice->stripe_subscription_payment_invoice_object = json_encode($event->data->object, true);
                    $subscriptionIntentInvoice->save();
    
    
    
    
                }
    
    
    
    
                if ($event->type === 'payment_intent.payment_failed') {
                    $subscriptionIntentInvoice = new SubscriptionPaymentInvoice();
    
    
    
    
                    $subscriptionIntentInvoice->invoice_id = $eventData->id;
                    $subscriptionIntentInvoice->number = $eventData->number;
                    $subscriptionIntentInvoice->stripe_subscription_id = $eventData->subscription;
                    $subscriptionIntentInvoice->hosted_invoice_url = $eventData->hosted_invoice_url;
                    $subscriptionIntentInvoice->invoice_pdf = $eventData->invoice_pdf;
                    $subscriptionIntentInvoice->customer_name = $eventData->customer_name;
                    $subscriptionIntentInvoice->customer_email = $eventData->customer_email;
                    $subscriptionIntentInvoice->collection_method = $eventData->collection_method;
                    $subscriptionIntentInvoice->account_name = $eventData->account_name;
                    $subscriptionIntentInvoice->invoice_careted_at = Carbon::createFromTimestamp($eventData->created);
                    $subscriptionIntentInvoice->status = $eventData->status;
                    $customerTransaction->stripe_failed_message = $eventData->last_payment_error->message;
    
    
    
    
                    $subscriptionIntentInvoice->stripe_subscription_payment_invoice_object = json_encode($event->data->object, true);
                    $subscriptionIntentInvoice->save();
    
    
    
    
                }
    
    
    
    
                DB::commit();
    
    
    
    
                return response()->json(['status' => 'success']);
            } catch (\Exception $e) {
    
    
    
    
                DB::rollBack();
                return response()->json(['status' => 'error', 'message' => $e->getMessage()], 500);
            }
    
    
    
    
        }

About Author

rishabh

Leave a Reply

Your email address will not be published. Required fields are marked *

RCV Technologies: Elevate your online presence with expert Digital Marketing, SEO, Web Design, and Development solutions.