Encrypt Card Payments Across Multiple Payment Processors

This guide will help you build an app that processes encrypted card payments with multiple payment providers: to see what it looks like, watch this demo. Clone this GitHub repo or use the Replit to follow along.

If you're a developer building payments into your application, you may be considering Payment Card Industry Data Security Standard (PCI DSS) compliance. One way to reduce the scope of your compliance burden is to ensure that your app never touches credit card data in plaintext. This can be challenging if you need to integrate multiple payment processors and pass sensitive data to their APIs, but it's possible with Evervault Inputs and Outbound Relay.

Check out the PCI DSS for Developers and Evervault Input documentation for more information.

This guide will walk you through building a card payments app using Evervault Inputs (which we will refer to as Inputs from now on). Inputs encrypts customer card data and keeps it encrypted as it moves from your client to your server. You can then pass the encrypted card data to multiple payment processors, such as and Stripe, where Outbound Relay automatically decrypts the card details. You can add additional payment processors as needed.


To run the code, you will need the following accounts:

Setting up your payments app

Clone this examples repo and open it in your favourite code editor. Navigate to the working directory.

git clone
cd encrypted-multi-psp-example

Next, install the dependencies, which includes the Evervault, Stripe, and Checkout SDKs to encrypt and send payments. Other dependencies required are the Node Fetch module to use the Fetch API and the dotenv module to load environment variables. Then run the code.

npm install
npm run dev

If you don't have an Evervault app yet, you'll create one in the next step.

Create an Evervault app

You’ll need an Evervault App dedicated to this project, so let’s set that up first. Go to Evervault, and in your dashboard, click Create App.

Once you’ve created your App, click on App Settings. This will give you access to your App ID and API Key, which you will need later on to add as environment variables. You can also access your Team ID and App ID from the URL of the page you are currently on:[team_team-id]/[app_app-id]/settings.

You’re officially set up with Evervault! Now you can add Inputs.

Initialize Inputs

You’ll use Inputs to create the form that collects cardholder data. When you use Inputs, it will be served within an iFrame that is hosted on Evervault’s PCI-compliant infrastructure, so all actions on card data (like validity checks and encryption operations) only occur within an Evervault context.

Open up public/index.html, and initialize the SDK by adding your Team ID and App ID which you created in the previous section.

const evervault = new Evervault('team_yourTeamID', 'app_yourAppID')

Now if you go to localhost:8080 in your browser, you should see the following:

Screenshot of input form

Next, you'll add in details required to use Stripe.

Add Stripe

Before you can send any payments from the server, you’re going to need a Stripe API key which you’ll store in a .env file. An example file called .env.example is included as part of the starter app, so rename it to.env.

mv .env.example .env

Next, go to your Stripe API keys dashboard. You should see a Publishable key and a Secret key. Copy the Secret key.

Screenshot of Stripe dashboard

Add the STRIPE_API_KEY to the .env file. It should look like STRIPE_API_KEY="sk_test_YOUR-SECRET-KEY".

To see where you are passing data to Stripe, navigate to the paymentProviders directory and open stripe.js. You should see this at the top of the file:

const Stripe = require('stripe')
const stripe = Stripe(process.env.STRIPE_API_KEY)
const PROVIDER_NAME = 'Stripe'

This will create an instance of the Stripe object, which is your entry point to the rest of the Stripe.js SDK. You will also declare a PROVIDER_NAME of ‘Stripe’ for the logic you will add in later on to differentiate between providers.

The makePayment() method is what will send your payment to Stripe:

const paymentMethod = await stripe.paymentMethods.create({
type: 'card',
card: {
number: options.card.number,
exp_month: options.card.expMonth,
exp_year: options.card.expYear,
cvc: options.card.cvc,
const paymentIntent = await stripe.paymentIntents.create({
amount: options.amount,
currency: options.currency,
confirm: true,
if (paymentIntent.status === 'succeeded') {
return {
provider: PROVIDER_NAME,
status: 'success',
return {
provider: PROVIDER_NAME,
status: 'failure',

The Stripe paymentMethod object is part of the Payment Method API and will allow you to create a payment type of “card,” but you could also utilise this for other forms of payment such as Buy Now Pay Later, direct debit via a bank, or a digital wallet.

You then pass the ID of the paymentMethod to the paymentIntent, which will be used to initialise the payment flow within Stripe.

Now, you can finally test out the payment. Stripe has a number of test card numbers available to use. For testing purposes, let’s use:

Card Number: 5555555555554444
Date : 12/34
CVC : 333

If you try to input the test card data and click checkout, you will see in your terminal that you’re getting a 402 error. This is because the card number is currently being sent in its encrypted form, but it’s not decrypting when it reaches the Stripe API.

If you check your terminal, you should be able to see the card object printed out. You’ll notice the encrypted strings as values for both the card number and the cvc:

"type": "visa",
"number": "ev:Tk9D:RmyB+raxNZPFP2ah:AofEVolV5In+lxkpNyk14Cndpo5rw0nMm74PJSjHbETH:j7ygGv5am24WL7yr0Dsq+gvMUT8R/bi/RqYlayjOMIw:$",
"cvc": "ev:Tk9D:KGck7r6WuF7Mtz7R:AofEVolV5In+lxkpNyk14Cndpo5rw0nMm74PJSjHbETH:DBrBUVbXOHY901eOhup2TovQNw:$",
"expMonth": "12",
"expYear": "34",
"track": { "fullTrack": "", "trackOne": "", "trackTwo": "" },
"name": "",
"swipe": false,
"lastFour": "4242",
"bin": "424242"

To fix this issue, you’ll need to enable Outbound Relay, which will decrypt the sensitive fields during the request to Stripe.

Enable Outbound Relay

To encrypt data in transit as it passes to third-party APIs, you’ll use Outbound Relay.

First add your Evervault API Key to the .env. This can be a key scoped specifically for Outbound Relay or can have multiple permissions as long as Outbound Relay is included.

To see where Outbound Relay is enabled in your code, open up the index.js file, and you will notice it below the PaymentProviders object:

const evervault = new Evervault(process.env.EVERVAULT_API_KEY)
const mySecret = process.env.EVERVAULT_API_KEY

This will enable Outbound Relay, so your card data will be decrypted (but only when it reaches the Stripe API).

The last step is to add as an outbound destination in your Evervault dashboard. In your dashboard, under Outbound Relay, click Add Destination and add It should look like the below. Then, click Add Outbound Destination.

Setting up Outbound Relay

Let’s test it out to see if it works!

Try out a successful payment

Go back to http://localhost:8080/ and try sending the payment again using the card details you used previously. This time, the payment should be successful.

If you go to your Stripe payments dashboard, you will see that the payment was successfully received by Stripe.

Successful payment in the Stripe dashboard

You will also see the activity logged in your Evervault Outbound Relay dashboard for the destination. If there was an error, you could see more details about what might have happened. A common error is improperly setting the host destination, so if you’re not seeing any activity in the logs, make sure the destination is defined correctly.

Outbound Relay activity log

Well done; your app should now work. If you’re interested in adding an additional payment provider, you can keep going with the guide to add as an additional outbound destination.

This guide does not cover implementing 3D Secure (3DS), a fraud protection measure that requires customers to complete an additional verification step with a card issuer during the payment process. This may be required for your business. Check your provider's documentation to learn more about 3DS and setup options.


To access the API, you will need a secret key, a public key, and a channel ID. Log in to your Checkout test account and go to the Developer Overview. Click Create a new key. developer dashboard

First, create a public API key. Then paste it into your .env. It should look like CHECKOUT_COM_PUBLIC_KEY="pk_sbox_XXXXXXXXXXX”.

When you create the key, you will be given the option to allow any processing channel, or choose specific channels. For the sake of this demo, you can leave it set to “Allow any processing channel.” Find the processing channel ID next to the channel checkbox (looks like pc_XXXXXXXXX) and add it to the .env file. api key creation

Repeat the process to create a secret API key. It will look like sk_sbox_XXXXXXX. Be sure to set it as an environment variable as soon as it’s displayed; you won’t be able to access it again.

Now you have everything you need to connect to the Checkout API. If you open the PaymentProviders directory and open the checkoutcom.js file you will see the code used to send a payment to For additional details on the API, you can see the documentation for Payments here.

Nearly there! The last step is to set * as a destination in the Outbound Relay section of your Evervault dashboard.

Set as a destination in Outbound Relay

This step will look familiar. Open your Evervault dashboard again and go to Outbound Relay. Enable * as a destination. Note that you will use the wildcard here to select requests made to any subdomains of This is because there is a slight difference between the sandbox and production domains of, but if we use this configuration, it will handle both.

If you have multiple Evervault apps, be sure you are in the one you set up at the beginning of the guide.

Make a test payment using the same credit card number 4242424242424242. This time, it should route to If you check your payments dashboard, you will see the transaction went through. successful payment

You now have a feature that processes encrypted payments across multiple payment service providers!


In this guide, you built a fully encrypted card payments feature across multiple payment processors using Evervault Inputs and Outbound Relay, Stripe, and If you ran into an issue or have any questions about this guide, feel free to raise them on GitHub or drop them in the Evervault Discord. Happy Encrypting!