Implementing Hosted Checkout with ANZ Worldline Payment Solutions in Next.js

As developers, integrating secure and efficient payment solutions into our applications is crucial. In this post, we’ll walk through implementing a hosted checkout solution using ANZ Worldline Payment Solutions in a Next.js application. This approach o…


This content originally appeared on DEV Community and was authored by Abdur Rakib Rony

As developers, integrating secure and efficient payment solutions into our applications is crucial. In this post, we'll walk through implementing a hosted checkout solution using ANZ Worldline Payment Solutions in a Next.js application. This approach offers a seamless payment experience while maintaining high security standards.

What is Hosted Checkout?
Hosted Checkout is a payment solution where the payment form is hosted by the payment provider. This method simplifies PCI DSS compliance as sensitive card data is handled directly by the provider's secure systems.

Prerequisites

A Next.js application
An account with ANZ Worldline Payment Solutions
Basic knowledge of React and API routes in Next.js

Setting Up the Project
First, let's set up our Next.js project structure:

src/
  app/
    api/
      create-hosted-checkout/
        route.js
      payment-details/
        [paymentId]/
          route.js
    checkout/
      page.jsx
    payment-result/
      page.jsx
    page.jsx

Implementing the Hosted Checkout

  1. Create the Hosted Checkout API Route In src/app/api/create-hosted-checkout/route.js:
import { NextResponse } from "next/server";
const onlinePaymentsSdk = require("onlinepayments-sdk-nodejs");

const client = onlinePaymentsSdk.init({
    host: 'payment.preprod.anzworldline-solutions.com.au',
    apiKeyId: 'YOUR_API_KEY_ID',
    secretApiKey: 'YOUR_SECRET_API_KEY',
    integrator: 'OnlinePayments',
});

const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:3000';

export async function POST(request) {
    const createHostedCheckoutRequest = {
        order: {
            amountOfMoney: {
                amount: 10 * 100, // 1000 cents AUD = $10
                currencyCode: 'AUD',
            },
        },
        hostedCheckoutSpecificInput: {
            returnUrl: `${baseUrl}/payment-result`,
        },
    };

    try {
        const response = await client.hostedCheckout.createHostedCheckout(
            'YOUR_MERCHANT_ID',
            createHostedCheckoutRequest,
            null
        );

        return NextResponse.json(response);
    } catch (error) {
        console.error("Error creating payment:", error);
        return NextResponse.json(
            { error: "Failed to create payment", details: error.message },
            { status: 500 }
        );
    }
}
  1. Implement the Checkout Page In src/app/checkout/page.jsx:
"use client";
import React, { useState, useEffect } from "react";
import { CreditCard } from "lucide-react";

export default function CheckoutPage() {
    const [res, setRes] = useState(null);

    useEffect(() => {
        if (res && res.body && res.body.redirectUrl) {
            window.location.href = res.body.redirectUrl;
        }
    }, [res]);

    const submitForm = async () => {
        try {
            const response = await fetch("/api/create-hosted-checkout", {
                method: "POST",
            });
            const data = await response.json();
            setRes(data);
        } catch (error) {
            console.error("Error during checkout:", error);
        }
    };

    return (
        <div className="min-h-screen py-6 flex flex-col justify-center items-center container mx-auto">
            <button
                className="border flex items-center rounded-lg p-2 bg-fuchsia-500 font-semibold text-white hover:bg-fuchsia-600 transition-colors"
                onClick={submitForm}
            >
                <CreditCard className="mr-2 h-5 w-5" /> Checkout
            </button>
            {res && (
                <div className="border rounded-lg p-10 mt-10 break-words max-w-full overflow-x-auto">
                    <p>Redirecting to payment page...</p>
                    <pre className="mt-4 text-sm">
                        {JSON.stringify(res, null, 2)}
                    </pre>
                </div>
            )}
        </div>
    );
}

3. Handle Payment Result
Create an API route to fetch payment details:
In src/app/api/payment-details/[paymentId]/route.js:

import { NextResponse } from "next/server";
const onlinePaymentsSdk = require("onlinepayments-sdk-nodejs");

const client = onlinePaymentsSdk.init({
    host: 'payment.preprod.anzworldline-solutions.com.au',
    apiKeyId: 'YOUR_API_KEY_ID',
    secretApiKey: 'YOUR_SECRET_API_KEY',
    integrator: 'OnlinePayments',
});

export async function GET(request, { params }) {
    const hostedCheckoutId = params.paymentId;

    if (!hostedCheckoutId) {
        return NextResponse.json(
            { error: "Hosted Checkout ID is required" },
            { status: 400 }
        );
    }

    try {
        const hostedCheckoutStatus = await client.hostedCheckout.getHostedCheckout(
            'YOUR_MERCHANT_ID',
            hostedCheckoutId,
            null
        );

        return NextResponse.json(hostedCheckoutStatus);
    } catch (error) {
        console.error("Error getting payment details:", error);
        return NextResponse.json(
            { error: "Failed to get payment details", details: error.message },
            { status: 500 }
        );
    }
}

Then, create a page to display the payment result:
In src/app/payment-result/page.jsx:

"use client";
import React, { useEffect, useState } from "react";
import { useSearchParams } from "next/navigation";

export default function PaymentResultPage() {
    const [paymentDetails, setPaymentDetails] = useState(null);
    const [error, setError] = useState(null);
    const searchParams = useSearchParams();
    const hostedCheckoutId = searchParams.get("hostedCheckoutId");

    useEffect(() => {
        if (hostedCheckoutId) {
            fetch(`/api/payment-details/${hostedCheckoutId}`)
                .then((response) => {
                    if (!response.ok) {
                        throw new Error('Network response was not ok');
                    }
                    return response.json();
                })
                .then((data) => setPaymentDetails(data))
                .catch((error) => {
                    console.error("Error fetching payment details:", error);
                    setError("Failed to fetch payment details. Please try again.");
                });
        }
    }, [hostedCheckoutId]);

    if (error) {
        return <div className="text-red-500">{error}</div>;
    }

    if (!paymentDetails) {
        return <div>Loading payment details...</div>;
    }

    return (
        <div className="p-4">
            <h1 className="text-2xl font-bold mb-4">Payment Result</h1>
            <pre className="bg-gray-100 p-4 rounded overflow-x-auto">
                {JSON.stringify(paymentDetails, null, 2)}
            </pre>
        </div>
    );
}

Conclusion
With these components in place, you've successfully implemented a hosted checkout solution using ANZ Worldline Payment Solutions in your Next.js application. This approach provides a secure and seamless payment experience for your users while simplifying PCI DSS compliance for your application.
Remember to replace placeholder values like YOUR_API_KEY_ID, YOUR_SECRET_API_KEY, and YOUR_MERCHANT_ID with your actual credentials from ANZ Worldline Payment Solutions.
By leveraging hosted checkout, you can focus on building great features for your application while leaving the complexities of payment processing to the experts.


This content originally appeared on DEV Community and was authored by Abdur Rakib Rony


Print Share Comment Cite Upload Translate Updates
APA

Abdur Rakib Rony | Sciencx (2024-09-26T20:25:40+00:00) Implementing Hosted Checkout with ANZ Worldline Payment Solutions in Next.js. Retrieved from https://www.scien.cx/2024/09/26/implementing-hosted-checkout-with-anz-worldline-payment-solutions-in-next-js/

MLA
" » Implementing Hosted Checkout with ANZ Worldline Payment Solutions in Next.js." Abdur Rakib Rony | Sciencx - Thursday September 26, 2024, https://www.scien.cx/2024/09/26/implementing-hosted-checkout-with-anz-worldline-payment-solutions-in-next-js/
HARVARD
Abdur Rakib Rony | Sciencx Thursday September 26, 2024 » Implementing Hosted Checkout with ANZ Worldline Payment Solutions in Next.js., viewed ,<https://www.scien.cx/2024/09/26/implementing-hosted-checkout-with-anz-worldline-payment-solutions-in-next-js/>
VANCOUVER
Abdur Rakib Rony | Sciencx - » Implementing Hosted Checkout with ANZ Worldline Payment Solutions in Next.js. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2024/09/26/implementing-hosted-checkout-with-anz-worldline-payment-solutions-in-next-js/
CHICAGO
" » Implementing Hosted Checkout with ANZ Worldline Payment Solutions in Next.js." Abdur Rakib Rony | Sciencx - Accessed . https://www.scien.cx/2024/09/26/implementing-hosted-checkout-with-anz-worldline-payment-solutions-in-next-js/
IEEE
" » Implementing Hosted Checkout with ANZ Worldline Payment Solutions in Next.js." Abdur Rakib Rony | Sciencx [Online]. Available: https://www.scien.cx/2024/09/26/implementing-hosted-checkout-with-anz-worldline-payment-solutions-in-next-js/. [Accessed: ]
rf:citation
» Implementing Hosted Checkout with ANZ Worldline Payment Solutions in Next.js | Abdur Rakib Rony | Sciencx | https://www.scien.cx/2024/09/26/implementing-hosted-checkout-with-anz-worldline-payment-solutions-in-next-js/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.