Learn how the Square Node.js SDK supports the common Square API features.
Some of the Square API patterns are used across various APIs. These include the following:
- Pagination - Many Square API operations limit the size of the response. When the result of the API operation exceeds the limit, the API truncates the result. You must make a series of requests to retrieve all the data. This is referred to as pagination.
- Idempotency key - Most Square APIs that perform create, update, or delete operations require idempotency keys to protect against making duplicate calls that can have negative consequences (for example, charging a card on file twice).
- Object versioning - Some Square resources (for example, the
Customer
object) have versions assigned. The version numbers enable optimistic concurrency, which is the ability for multiple transactions to complete without interfering with each other. - Clear API object fields - Square API update endpoints that support sparse updates allow you to clear fields by setting the value to
null
. Note thatupdateOrder
requires anX-Clear-Null: true
HTTP header to indicate that the request contains anull
field update.
These Square API patterns are exposed in the Square Node.js SDK.
Square API pagination support lets you split a full query result set into pages that are retrieved over a sequence of requests. For example, when you call client.customers.list()
, you can limit the number of customers returned per page in the response. You can check whether there are more customers to retrieve using customerPager.hasNextPage()
. If there's another page, you can get those results using customerPager.getNextPage()
.
To get a single page of data, use the customerPager.data
property. To iterate over all customers, you can use a for await(… of …)
loop. The SDK makes additional HTTP requests to retrieve additional pages of data.
import { SquareClient, SquareError } from "square";
const client = new SquareClient({
token: process.env.SQUARE_ACCESS_TOKEN
});
listCustomers();
async function listCustomers() {
const limit = 10;
try {
let customerPager = await client.customers.list({
limit,
sortField: "DEFAULT",
sortOrder: "DESC"
});
for await (const customer of customerPager) {
console.log("customer: ID: " + customer.id,
"Version: " + customer.version + ",",
"Given name: " + customer.givenName + ",",
"Family name: " + customer.familyName);
}
} catch (error) {
if (error instanceof SquareError) {
console.error("Error occurred: " + error.message);
} else {
console.error("Unexpected error occurred: ", error);
}
}
}
When an application calls a Square API, it must be able to repeat an API operation when needed and get the same result each time. For example, if a network error occurs while updating a catalog item, the application might retry the same request and must ensure that the item updates only once.
This behavior is called idempotency. Most Square APIs that modify data (create, update, or delete) require you to provide an idempotency key that uniquely identifies the request. This allows you to retry the request if necessary, without duplicating work.
You can provide a custom unique key or simply generate one. There are language specific functions that you can use to generate unique keys. For more information, see Idempotency. The following example shows how the idempotencyKey
is generated in a Node.js application to create an order:
import { SquareClient, SquareError } from "square";
import { randomUUID } from 'crypto';
const client = new SquareClient({
token: process.env.SQUARE_ACCESS_TOKEN,
});
async function createOrder() {
try {
const idempotencyKey = randomUUID();
const locationId = getLocationId();
const order = await client.orders.create({
idempotencyKey: idempotencyKey,
order: {
locationId: locationId,
lineItems: [
{
name: "New Item",
quantity: "1",
basePriceMoney: {
amount: BigInt(100),
currency: "USD",
},
},
],
},
});
} catch (error) {
if (error instanceof SquareError) {
console.error("Error occurred: " + error.message);
} else {
console.error("Unexpected error occurred: ", error);
}
}
}
createOrder();
Some Square API resources support versioning. For example, each Customer
object has a version field. Initially, the version number is 0. Each update increases the version number. If you don't specify a version number in the request, the latest version is assumed.
This resource version number enables optimistic concurrency; multiple transactions can complete without interfering with each other. As a best practice, you should include the version field in the request to enable optimistic concurrency. The value must be set to the current version. For more information, see Optimistic Concurrency.
The following code example updates a customer name. The update request also includes a version number. It succeeds only if the specified version number is the latest version of the customer object on the server.
import { SquareClient, SquareError } from "square";
const client = new SquareClient({
token: process.env.SQUARE_ACCESS_TOKEN,
});
async function updateCustomer() {
try {
let updateCustomerResponse = await client.customers.update(
{
customerId: "GZ48C4P2CWVXV7F7K2ZH795RSG",
givenName: "Fred",
familyName: "Jones",
version: BigInt(11)
}
);
} catch (error) {
if (error instanceof SquareError) {
console.error("Error occurred: " + error.message);
} else {
console.error("Unexpected error occurred: ", error);
}
}
}
updateCustomer();
For update operations that support sparse updates, your request only needs to specify the fields you want to change (along with any fields required by the update operation). If you want to clear a field without setting a new value, set its value to null
. For more information, see Clear a field with a null.
The following client.locations.update()
example clears the twitterUsername
field and sets the websiteUrl
field:
import { SquareClient, SquareError } from "square";
const client = new SquareClient({
token: process.env.SQUARE_ACCESS_TOKEN
});
async function updateLocation() {
try {
let updateLocationResponse = await client.locations.update({
locationId: 'M8AKAD8160XGR',
location: {
twitterUsername: null,
websiteUrl: 'https://developer.squareup.com',
},
});
console.log(updateLocationResponse.location);
} catch (error) {
if (error instanceof SquareError) {
console.error("Error occurred: " + error.message);
} else {
console.error("Unexpected error occurred: ", error);
}
}
};
updateLocation();
updateOrder
requests require an additional header.
If you're using null
to clear fields in an order, you must add the X-Clear-Null: true
HTTP header to signal your intention. In the Square Node.js SDK, you can pass additional headers
to each method for this purpose.
await client.orders.update(
{
orderId: "K1BZGPD0QB7ER26AFXFYKBG9K0",
idempotencyKey: idempotencyKey,
order: {
locationId: locationId,
referenceId: null
},
},
{
headers: {
"X-Clear-Null": "true"
}
}
);