Payment API and WebSDK

I am trying to use the WebSDK and Payment API in express.js and react. I keep on getting a 401 error with authentication.

This is what i have on my server.js using express.

const Square = require(“square”);
const squareClient = new Square.SquareClient({
accessToken: process.env.SQUARE_ACCESS_TOKEN,
environment: Square.SquareEnvironment.Sandbox, // Change to Environment.Production when live
});

app.post(“/create-payment”, async (req, res) => {
const {sourceId, amount, currency} = req.body;

try {
    const paymentsApi = squareClient.payments;

    const response = await paymentsApi.create({
        sourceId,
        idempotencyKey: crypto.randomUUID(),
        amountMoney: {
            amount: BigInt(amount),
            currency: currency || "USD",
        },
    })

    res.json({
        success: true,
        payment: response.result.payment
    })
} catch (error) {
    console.error("Error processing payment", error);
    res.status(500).json({
        success: false,
        error: error.message,
    })
}

})

And this is what I have on my react .jsx file

useEffect(() => {
async function initializeSquare() {
if (!window.Square) {
console.error(“Square is not available.”);
return;
}

        try {
            const paymentsInstance = await window.Square.payments(
                applicationID
                locaitonID
            );

            setPayments(paymentsInstance);
        } catch (error) {
            console.error("Error initializing Square:", error);
        }
    }

    initializeSquare();
}, []);

useEffect(() => {
    if (!payments || !cardContainerRef.current) return;

    async function attachCard() {
        try {
            const cardInstance = await payments.card();
            await cardInstance.attach(cardContainerRef.current);
            setCard(cardInstance);
        } catch (error) {
            console.error("Error attaching Square card:", error);
        }
    }

    if (!card) attachCard();
}, [payments]);

const [isProcessing, setIsProcessing] = useState(false); // Track payment status

const handleCheckout = async () => {
    if (!card) {
        console.error("Square payment form not initialized.");
        return;
    }

    try {
        const result = await card.tokenize();
        console.log("Tokenization result:", result);

        if (result.status === "OK") {
            const response = await fetch("http://localhost:5001/create-payment", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    sourceId: result.token,
                    amount: totalAmount * 100, // Convert dollars to cents
                    currency: "USD"
                }),
            });

            const data = await response.json();
            console.log("Payment response:", data);

            if (data.payment && data.payment.status === "COMPLETED") {
                setOrderComplete(true);
                alert("Payment successful!");
            } else {
                console.error("Payment failed:", data);
                alert("Payment failed. Check console for details.");
            }
        } else {
            console.error("Tokenization failed:", result);
            alert("Card tokenization failed.");
        }
    } catch (error) {
        console.error("Payment error:", error);
        alert("An error occurred during payment.");
    }
};

I just don’t know if I have it setup right or if I am missing something. I am just learning this stuff as I am building my first full stack website for my family’s company. I am still going to college so I am a bit lost.

:wave: I’m Square Dev AI, here to help answer your question!
Based on the information you’ve provided, the following documentation will help answer your question:

Additional Documentation

Square Node.js SDK Quickstart
Deploy the Server
In-App Payments SDK Quickstart

If this documentation helped you find a solution, please check the box indicating that this reply solves the problem.
Otherwise one of our Developer Advocates will provide additional assistance shortly.

The 401 error typically indicates an issue with authentication. In your case, it seems like the issue might be with the Square access token. Here are a few things you can check:

  1. Ensure that the SQUARE_ACCESS_TOKEN environment variable is correctly set in your server environment. You can print it out in your server console to verify.

  2. Make sure that the access token you’re using is correct and has the necessary permissions. If you’re using a Sandbox access token, ensure that you’re making requests to the Sandbox environment, and vice versa for production.

  3. In your React code, you’re initializing the Square payments instance with applicationID and locationID. Make sure these values are correct and correspond to your Square account.

  4. In your server-side code, you’re using the Square.SquareClient to create a new Square client. Make sure that the accessToken and environment are correctly set here.

  5. Ensure that the endpoint you’re hitting (/create-payment) is correctly set up in your Express.js server and is reachable.

If you’ve checked all of these and are still encountering issues, it might be helpful to look at the exact error message you’re getting back from the API for more clues.

This answer was reviewed by @Bryan-Square.

Error processing payment SquareError: Status code: 401
Body: {
“errors”: [
{
“category”: “AUTHENTICATION_ERROR”,
“code”: “UNAUTHORIZED”,
“detail”: “This request could not be authorized.”
}
]
}
at Payments. (C:\Users\noahl\WebstormProjects\bittybird-co\server\node_modules\square\api\resources\payments\client\Client.js:249:23)
at Generator.next ()
at fulfilled (C:\Users\noahl\WebstormProjects\bittybird-co\server\node_modules\square\api\resources\payments\client\Client.js:41:58)
at process.processTicksAndRejections (node:internal/process/task_queues:105:5) {
statusCode: 401,
body: { errors: [ [Object] ] },
errors: [
{
category: ‘AUTHENTICATION_ERROR’,
code: ‘UNAUTHORIZED’,
detail: ‘This request could not be authorized.’
}
]
}
This is the error I am getting on my server when I try to make a payment

An authentication error is a configuration error. Are you targeting the correct environment? Is this with sandbox or production? :slight_smile:

This is in sandbox. I have the environment set to sandbox on my server. I also know that I am getting the body from my react website correctly and creating the correct sourceId. So i don’t know why the authentication error is happening because I tested with curl with my access token and everything came out with a 200 code. I don’t know if my oauth is setup correctly or not though either

What’s the Web Payments SDK JavaScript reference configured too? Is it sandbox.web.squarecdn.com/v1/square.js or web.squarecdn.com/v1/square.js ? :slight_smile:

I don’t know why to find that.
const Checkout = () => {
const { cartItems } = useCart();
const [orderComplete, setOrderComplete] = useState(false);
const [payments, setPayments] = useState(null);
const [card, setCard] = useState(null);
const cardContainerRef = useRef(null);

const totalAmount = 100;
    // cartItems.reduce((total, item) => total + item.price * item.quantity, 0);

useEffect(() => {
    async function initializeSquare() {
        if (!window.Square) {
            console.error("Square is not available.");
            return;
        }

        try {
            const paymentsInstance = await window.Square.payments(
                "sandbox-sq0idb-CwIDy2fpZxmfqawpiU3xTw",
                "L32T6NP2XFTSJ"
            );

            setPayments(paymentsInstance);
        } catch (error) {
            console.error("Error initializing Square:", error);
        }
    }

    initializeSquare();
}, []);

useEffect(() => {
    if (!payments || !cardContainerRef.current) return;

    async function attachCard() {
        try {
            const cardInstance = await payments.card();
            await cardInstance.attach(cardContainerRef.current);
            setCard(cardInstance);
        } catch (error) {
            console.error("Error attaching Square card:", error);
        }
    }

    if (!card) attachCard();
}, [payments]);

const [isProcessing, setIsProcessing] = useState(false); // Track payment status

const handleCheckout = async () => {
    if (!card) {
        console.error("Square payment form not initialized.");
        return;
    }

    try {
        const result = await card.tokenize();
        console.log("Tokenization result:", result);

        if (result.status === "OK") {
            const response = await fetch("http://localhost:5001/create", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    sourceId: result.token,
                    amount: totalAmount * 100, // Convert dollars to cents
                    currency: "USD"
                }),
            });

            const data = await response.json();
            console.log("Payment response:", data);

            if (data.payment && data.payment.status === "COMPLETED") {
                setOrderComplete(true);
                alert("Payment successful!");
            } else {
                console.error("Payment failed:", data);
                alert("Payment failed. Check console for details.");
            }
        } else {
            console.error("Tokenization failed:", result);
            alert("Card tokenization failed.");
        }
    } catch (error) {
        console.error("Payment error:", error);
        alert("An error occurred during payment.");
    }
};

That is my code. This is the only scrip I have with square and I don’t see either of those so I am assuming I have it setup wrong.

Where did you get the example that your running? :slight_smile:

Sorta myself and with some help from ChatGPT just trying to add what I knew with react and what i didn’t know on how to do the payments with square stuff. I couldnt find what I needed to in the docs. I have my own express server that I am making api calls to which is why I am trying to fetch my own local host but know that I have done a bit more digging I am not sure if that is what I need to be doing with square. I just might be confused completely on the setup of everything.

Directly making API calls to generate a source_id isn’t supported. You’ll have to use our generated iframe to generate the tokenized card that you pass to CreatePayment.

Have you taken a look at the React Web Payments SDK from our partner? :slight_smile:

1 Like

Thank you, I just ran into a different issue with the api call. It is passing now but it is saying my source_id and idempotency_key is blank. This is what I have. My code does say taht a sourceId is coming through of ‘cnon:CA4SEBAnr5sTlFYGNrjZfbuh6vkYASgC’

app.post(“/create”, async (req, res) => {
const { sourceId, amount, currency } = req.body;
console.log(“Received payment request:”, { sourceId, amount, currency });

try {
    if (!sourceId || !amount || amount <= 0) {
        return res.status(400).json({ success: false, error: "Invalid payment details" });
    }

    const response = await fetch("https://connect.squareupsandbox.com/v2/payments", {
        method: "POST",
        headers: {
            "Authorization": `Bearer ${process.env.SQUARE_ACCESS_TOKEN}`,
            "Content-Type": "application/json",
            "Square-Version": "2023-12-13"
        },
        body: JSON.stringify({
            sourceId: sourceId,
            idempotencyKey: crypto.randomUUID(), // Prevents duplicate transactions
            amountMoney: {
                amount: Math.round(amount), // Ensure amount is in cents
                currency: currency || "USD"
            },
            autocomplete: true
        })
    });

    const data = await response.json();
    console.log("Square API Response:", data);

    if (response.ok) {
        res.json({ success: true, payment: data.payment });
    } else {
        console.error("Square Payment Failed:", data);
        res.status(500).json({ success: false, error: data.errors || "Payment failed" });
    }

} catch (error) {
    console.error("Error processing payment:", error);
    res.status(500).json({ success: false, error: error.message });
}

});

Yay, progress you got a tokenized card. There must be something wrong with the way it’s passed to the CreatePayment server side call if the error your getting is that it’s blank. :slight_smile:

I made a few changes with the json being passed and I got it working

Fantastic! Glad to hear that you got it to work! :slight_smile: