" width="1000" style="--opacity:1">
Sam Magura
Braintree is one of the world's leading payment platforms. On a basic level, Braintree allows you to charge customers from your web app. The service is owned by PayPal and supports a wide array of payment methods — card, PayPal, Venmo, Apple Pay, and Google Pay — so your customers can check out with ease no matter which payment method they prefer.
Braintree provides a powerful and modern GraphQL API to enable you to quickly integrate with the services' many features without having to add any dependencies to your project. This article will guide you through implementing a basic payment use case — charging a credit card — using the Braintree GraphQL API from Node.js and React, specifically Next.js . That said, it is straightforward to adapt the code shown in this guide to any web app tech stack. That's the beauty of integrating via an HTTP-based API rather than a language-specific SDK.
Security is of the utmost importance whenever financial data is involved, so it's critical that we handle our Braintree API key safely. That's why we will store the Braintree API key in the Zero secrets manager and fetch it at runtime using the official Zero TypeScript SDK. If using a language other than JavaScript or TypeScript, you can use one of Zero's other SDKs , or interface with Zero's GraphQL API directly.
🔗 The full code for this example is available in the zerosecrets/examples GitHub repository.
To start using Braintree, you'll need to sign up for a Sandbox account. The Sandbox allows you to develop against the API with zero risk of making a real charge.
Once logged in, you will be presented with your public key, private key, and merchant ID. If not, click the gear icon in the upper right corner of the page and select "API". Your API key is the public key followed by the private key encoded in base 64. You can easily obtain your API key by running
Just remember to replace v4ndq314c2s5c28r
with your public key and 93b78bc88be90d93ac282e50ae569fdd
with your private key.
⚠️ Both your private key and API key provide access to your account, so they must be kept secure. Be careful not to commit either of these values to a git repository or access them on the client side.
Server-side calls to the GraphQL API use the API key (not the private key), so it's the API key which we need to copy into Zero:
The simplest way to use Braintree is to accept a one-time payment. The excellent Braintree docs explain how this process works at a technical level:
This design is great because the customer's payment information never passes through your server. This sidesteps a whole range of serious security and privacy issues that can arise when handling sensitive financial information.
Let's bootstrap a new Next.js project so we can start integrating with Braintree:
Our app will contain a single page with a "Submit fake payment" button that submits a hardcoded credit card and billing address to the server. When the server receives the request, it creates a transaction in Braintree and returns the transaction ID and status to the client.
As described in the previous section, the first step is to request a client token . This requires your Braintree API key, so the request must be made on the server side. We can add server-side logic to a Next.js page by defining a getServerSideProps
function in the same file as the page:
With the general structure of the code in place, let's work on filling in getServerSideProps
. First, we'll need to fetch the Braintree API key from Zero:
The API key will be used in multiple different places in the app, so it's best to create a fetchBraintreeApiKey
helper function so that the code for calling Zero is not duplicated. The function uses the Zero TypeScript SDK to exchange your Zero token for the Braintree API key:
Next, we need to execute the GraphQL mutation
Let's define this as a string constant in a new src/braintreeApi/graphql.ts
file:
Let's also define a TypeScript type for the response we expect the mutation to return:
Now we have all the building blocks necessary to make the GraphQL call in getServerSideProps
:
This code makes use of a few constants which can be defined in braintreeApi/constants.ts
:
If you run the project with ZERO_TOKEN='your-zero-token' npm run dev
, you should get a long string like eyJ2ZXJzaW9uIjoyLCJhdXRob3JpemF0...
for the client token.
The client token is actually a base 64 encoded JSON string which contains an authorization fingerprint. The fingerprint can be extract from the client token like so
It is this fingerprint that must be passed in the Authorization
header when making GraphQL requests on the client side.
Now that the frontend has an authorization fingerprint, the next step is to collect the user's payment information and exchange it for a token (payment method ID) using the mutation
The exact data required to form a TokenizeCreditCardInput
can be determined from Braintree's GraphQL Explorer , specifically the "Docs" sidebar on the right.
TypeScript types should be added to braintreeApi/graphql.ts
to represent TokenizeCreditCardInput
and the input types it references, such as CreditCardInput
and AddressInput
.
In a real-world application, the UI would display a form where the user can enter their credit card information and billing address. To keep this demonstration simple, we'll simply hardcode a fake billing address and credit card:
When the user clicks the "Submit fake payment" button in the UI, we'll call the tokenizeCreditCard
mutation with the hardcoded credit card. This returns a payment method ID which we pass to our backend, which will use the payment method ID to charge the credit card.
The only remaining step is to implement the /api/createTransaction
method on the backend. In Next.js, you can create a backend API method by placing files in the src/pages/api
directory, so let's create the file src/pages/api/createTransaction.ts
.
The createTransaction
API route should accept a payment method ID in the request body and use it to call the Braintree API with the following mutation:
TypeScript types can be created for the input and response objects by using the GraphQL explorer as we did previously. The final code for the API route looks like this:
The string returned by this API method should be displayed in the UI so we know whether the integration with the Braintree Sandbox is working. If it worked, you'll see a string like
Congratulations, you just charged your first customer!
Once you wrap your head around the multi-step process that is required to submit a transaction to Braintree, the rest is straightforward thanks to the documentation provided in Braintree's GraphQL explorer. While Braintree does provide a few ready-made SDKs, calling the GraphQL API directly is likely to be the most flexible approach. It also keeps your node_modules
directory lean as it does not require any additional dependencies.