Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Physical Address
304 North Cardinal St.
Dorchester Center, MA 02124
Ready to take your Next.js app to the checkout lane? Let’s integrate Square payments and make your App Router application as smooth as a well-oiled cash register. 💰
Square offers a robust payment platform with developer-friendly APIs. It’s great for both online and offline payments, perfect for your Next.js e-commerce project.
Before we dive in, make sure you’ve got:
Got all that? Let’s square up! 🔲
First, let’s add the Square SDK to our project:
npm install square
Create a .env.local
file in your project root and add your Square credentials:
SQUARE_ACCESS_TOKEN=your_access_token_here
SQUARE_LOCATION_ID=your_location_id_here
Next.js Configuration
/** @type {import('next').NextConfig} */
const nextConfig = {
env: {
SQUARE_ACCESS_TOKEN: process.env.SQUARE_ACCESS_TOKEN,
SQUARE_LOCATION_ID: process.env.SQUARE_LOCATION_ID,
},
};
module.exports = nextConfig;
Let’s create a utility file to initialize our Square client:
Square Client Utility
import { Client, Environment } from 'square';
const squareClient = new Client({
accessToken: process.env.SQUARE_ACCESS_TOKEN,
environment: Environment.Sandbox, // Use Environment.Production for live payments
});
export default squareClient;
Now, let’s create an API route to handle payment creation:
Payment API Route
// app/api/create-payment/route.js
import { NextResponse } from 'next/server';
import squareClient from '../../../utils/squareClient';
export async function POST(req) {
const { sourceId, amount, currency } = await req.json();
try {
const response = await squareClient.paymentsApi.createPayment({
sourceId: sourceId,
amountMoney: {
amount: amount,
currency: currency,
},
locationId: process.env.SQUARE_LOCATION_ID,
});
return NextResponse.json({ payment: response.result.payment });
} catch (error) {
console.error('Payment error:', error);
return NextResponse.json({ error: error.message }, { status: 500 });
}
}
Let’s create a React component to handle our payment form:
Payment Form Component
'use client';
import { useState } from 'react';
import { SquarePaymentForm, CreditCardNumberInput, CreditCardExpirationDateInput, CreditCardPostalCodeInput, CreditCardCVVInput } from 'react-square-payment-form';
import 'react-square-payment-form/lib/default.css';
export default function PaymentForm() {
const [errorMessages, setErrorMessages] = useState([]);
const cardNonceResponseReceived = async (errors, nonce, cardData, buyerVerificationToken) => {
if (errors) {
setErrorMessages(errors.map(error => error.message));
return;
}
setErrorMessages([]);
try {
const response = await fetch('/api/create-payment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
sourceId: nonce,
amount: 100, // Amount in cents
currency: 'USD',
}),
});
const result = await response.json();
if (response.ok) {
console.log('Payment successful:', result.payment);
// Handle successful payment (e.g., show confirmation, update UI)
} else {
setErrorMessages([result.error]);
}
} catch (error) {
setErrorMessages(['Network error. Please try again.']);
}
};
return (
<SquarePaymentForm
applicationId="sandbox-sq0idb-YOUR-APP-ID"
locationId={process.env.NEXT_PUBLIC_SQUARE_LOCATION_ID}
cardNonceResponseReceived={cardNonceResponseReceived}
>
<fieldset className="sq-fieldset">
<CreditCardNumberInput />
<div className="sq-form-third">
<CreditCardExpirationDateInput />
</div>
<div className="sq-form-third">
<CreditCardPostalCodeInput />
</div>
<div className="sq-form-third">
<CreditCardCVVInput />
</div>
</fieldset>
<button className="sq-button" onClick={e => e.preventDefault()}>
Pay Now
</button>
{errorMessages.length > 0 && (
<div className="sq-error-message">
{errorMessages.map(errorMessage => (
<p key={errorMessage}>{errorMessage}</p>
))}
</div>
)}
</SquarePaymentForm>
);
}
Now, let’s use our PaymentForm
component in a page:
Checkout Page Component
import PaymentForm from '../components/PaymentForm';
export default function CheckoutPage() {
return (
<div className="container mx-auto px-4 py-8">
<h1 className="text-3xl font-bold mb-4">Checkout</h1>
<PaymentForm />
</div>
);
}
To keep your app in sync with Square events (like successful payments), you’ll want to set up a webhook endpoint:
Webhook Handler
// app/api/webhooks/square/route.js
import { NextResponse } from 'next/server';
import squareClient from '../../../../utils/squareClient';
export async function POST(req) {
const body = await req.json();
const signature = req.headers.get('x-square-signature');
if (!signature) {
return NextResponse.json({ error: 'No signature provided' }, { status: 400 });
}
try {
// Verify the webhook signature
const event = await squareClient.webhooksApi.verifyWebhook(JSON.stringify(body), signature);
// Handle different event types
switch (event.type) {
case 'payment.created':
// Handle new payment
console.log('New payment created:', event.data.object.payment);
break;
// Add more cases as needed
}
return NextResponse.json({ received: true }, { status: 200 });
} catch (err) {
console.error('Webhook error:', err);
return NextResponse.json({ error: 'Webhook error' }, { status: 400 });
}
}
And there you have it! You’ve just integrated Square payments into your Next.js 14 app using the App Router. Your users can now make payments smoother than a freshly polished countertop. 💳✨
Remember to:
Now go forth and monetize your Next.js app like a boss! 💰
Want to level up your Next.js skills even more? Check out these cash-money articles: