Accept Payments with Square and Svelte
Easily add payments to your Sveltekit app!
If the thought of implementing online payments makes your stomach churn, you’re not alone. Building an online payment flow can be very intimidating. Afterall, an unsecure payment process can have serious repercussions for your business. Luckily, Square is here to help relieve you of all your worries and get you up and running with a safe and secure payments implementation.
In this tutorial, we’re going to take you step-by-step through the process of integrating a simple and secure payment flow into your app. We’re going to use the Square Web Payments SDK and the Square Payments API to get us up and running so you can start accepting payments online. To help us out, we’re going to be using SvelteKit as our framework for this project. SvelteKit is a full stack framework that provides a lot of great features that will help simplify our payments implementation. By the end of this tutorial, you’ll have a fully functional and secure payment flow that accepts credit card payments. Here's what the final result will look like:
This tutorial requires a basic understanding of Svelte and SvelteKit. All of the code for this tutorial can be found in the accept-payments-with-square-and-svelte Github repo.
Before we dive into the details, checkout this demo that highlights each of the steps of implementing an end to end payment flow.
Now that we have a general idea of how to process a payment, let’s break down each step and dive into the details that make this work.
Create a Credit Card Payment Form
The first step of building a payment flow is creating a form that accepts credit cards. Fortunately for us, the Square Web Payments SDK takes care of a lot of the heavy lifting in this step. In order to use the Web Payments SDK, we need to add the following script
tag to the head
of our app.html
file.
With our script added, we can start to create our payment form. In our main +page.svelte
file, let's add the following form.
We can also add some CSS to style our button.
You'll notice that our form includes a div
with an id
of "card-container". This div
is meant to be a placeholder for where our card input field will go. We'll need to use the Square Web Payments SDK to create a secure input field in that slot. Let’s do this in a function called initializePaymentForm
.
There are three things going on in this initializePaymentForm
function. Let's break it down:
-
First, we're checking to make sure the
Square
object exists. This object comes from that script that we added earlier in thehead
. This won’t work without that script. -
Next, we're initializing the Web Payments SDK by calling
Square.payments(appId, locationId)
. I've definedappId
andlocationId
outside our function, just in case we need to use them anywhere else in our app. -
Finally, we initialize the Card payment method by calling
payments.card()
and storing that in a variable calledcard
. We then attach our card to the placeholderdiv
with anid
of "card-container" in order to get our card input to display on the page.
I've declared the card
variable outside the initializePaymentForm
function because we're going to be using it in other parts of the code later.
Our initializePaymentForm
function looks great, but now we need to call it somewhere to get our form set up. This is a perfect opportunity to use Svelte's await blocks.
This is how we can execute our initializePaymentForm
function. While the function is running, we'll see the text, "Loading...", on the screen. Once it completes, we'll see the card input field. If the function throws an error, we'll display the error message instead.
Tokenize the Payment Method
Ok, so we've got our payment form all set up. Now we need to handle the payment when the form is submitted. To do that, there is another piece to this payment puzzle that we need: tokenization.
Payment tokenization is the process of taking sensitive payment information and replacing it with a nonsensitive generated number called a token. We do this to protect the users’ payment information and add a level of security. If you’re worried about how to implement tokenization, don’t sweat it! Square takes care of this for you by providing a tokenize
method that you can call on your payment method. Let's take a look at how we add this to our implementation.
This function may look a little intimidating, but it's really only doing one thing, getting a token. You can see that this function takes in a payment method, and then calls the tokenize
method to get back a token for that payment. The rest of the function is error handling in case the tokenization process fails for some reason. Provided there aren't any errors, this function returns the token that we need to send to our server to process the payment. Speaking of which, let's take a look at how we can do that now.
Send the Token to the Server
Ok, so now we have a way to tokenize our payment method. Let's go ahead and send that token over to our server where it'll be processed. We'll want to do this anytime a user submits the payment form by clicking our "Pay $1.00" button, so let's attach a function called handlePaymentMethodSubmission
that we'll run on submit.
And now we can define that function as so:
The first thing we do in our handlePaymentMethodSubmission
function is use the tokenize
function that we just wrote to generate a token for our card
. Then we send a POST request to our payment endpoint and include our locationId
and token
in the body
. If you're confused about what this payment endpoint is, you should be! We haven't written it yet! That's the next step in our payment pipeline, so let's go create that endpoint now.
Process the Payment with the Payments API
To create an API endpoint in SvelteKit, we first need to create a folder under our routes
folder called api
. Then, within our api
folder, create another folder called payment
. Finally, within our payment
folder, create a file called +server.js
. This folder structure creates an API endpoint with the path /api/payment
and it's where we'll handle the POST request that we're sending from the client. Before we do that, though, we need to initialize the Square Payments API.
Square Payments API
Because we’re going to use the Square Payments API, we need to first install the Square Node.js SDK.
npm install square
With the SDK installed, we can import the Client
from Square at the top of our +server.js
file. Then we can initialize the paymentsApi
by providing an access token and environment type to the Client
.
The value of your Square access token can be found in your Square developer dashboard, under your specific application. We need to keep our access token hidden, so we’re storing it in an environment variable. SvelteKit uses Vite under the hood, so we need to create our environment variable in a .env
file and prefix it with VITE_
.
Handle the Request
Awesome! We’ve got all our setup in place, so let’s go ahead and write our request handler function that will be responsible for processing the payment. This handler is meant to handle a POST request, so we’ll export an async
function called POST
.
For an endpoint like this, Sveltekit provides us access to a request
object. We can call the json()
method on this object in order to get the contents of the request body. In our case that’s the locationId
and sourceId
.
Let’s pause for a minute here and take a look at everything we include in the request body to understand what each of them does.
idempotencyKey
: A unique string that identifies this request. To generate a unique string, we use therandomUUID
function from the Node.js crypto module. Don’t forget to import this at the top.sourceId
: The ID for the source of funds for the payment. In our case, this will be the payment token that is generated by the Square payment form. We’ll provide this token in the body of the POST request.amountMoney
: An object that defines the amount of money to be paid. In our case, we’re specifying the currency to be US dollars and the amount is in the smallest denomination of the currency type. So a value of 100 represents 100 cents or $1.00. We’re hardcoding this value for demonstration’s sake, but you can also send this value in the POST request for dynamic prices.
You can see all the options that you can pass to this method in the API reference.
Finally, after we await the result of creating the payment, we send the result back to the client with SvelteKit's json
function. Don’t forget to import that at the top as well.
Common Pitfall
While our endpoint looks complete, if we try to create a payment now, we’ll encounter this error on the server: TypeError: Do not know how to serialize a BigInt
. This error occurs because BigInt values aren’t serialized in JSON by default. To fix this, we need to define our own toJSON
method to return a string.
Now our endpoint is complete.
Display the Result
We're almost there, but there's one final piece I want to add in order to provide a more complete user experience. Our API endpoint sends a response back to our client, but our client doesn't do anything with that response yet. Let's add some functionality to report to the user whether or not the payment was processed successfully.
First, we'll create a variable called paymentStatus
that will store a string indicating the status of the payment.
Now we can set the value of paymentStatus
based on the response we receive from our POST request.
And finally, we can add this result to our page.
We’ll sprinkle in some CSS for the payment status message as well:
#payment-status-container { width: fit-content; font-family: Arial, Helvetica, sans-serif; color: #ffffff; background: #1a1a1a; display: flex; padding: 12px; border-radius: 6px; box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.1), 0px 0px 4px rgba(0, 0, 0, 0.1); margin: auto; margin-top: 36px;}
Now the page will provide feedback to our users on whether or not their payment was processed successfully.
Conclusion
So to recap, in this tutorial we covered the five steps required to build a complete end-to-end payment flow. We used the Square Web Payments SDK and the Square Payments API to accept and process a user’s payment. On top of that, all of this was wired together using Sveltekit as our framework.
This is a great start, but there’s so much more you can do with the web payments SDK. We didn’t even go into additional capabilities like custom styling and digital wallets. This tutorial is meant to provide you with a solid foundation from which you can start to add additional features. We can’t wait to see what you build from here.