Paze

Offer Paze in your checkout via Spreedly

Paze is a digital wallet that makes it easy for you to check out online. Offered by participating banks and credit unions, Paze allows you to purchase things online without having to share your actual card numbers. Paze supports eligible credit and debit cards issued by participating financial institutions.

With Paze, customers can experience a convenient checkout experience where they do not need to enter their 16-digit card numbers or create new usernames or passwords. Depending on your preference, customers can also use Paze to set up an account with your business, so they can build a relationship with you, not the wallet.

Onboarding

๐Ÿ“˜

In order to use Paze, you will need to first onboard with Paze.

This will provide you with several items that will be utilized during your integration:

Certificates

Since the payloads with Paze are encrypted, you will need a certificate with Paze and then to input that certificate into Spreedly. This will give Spreedly access to the secure payment method information from the Paze SDK.

Paze Certificate

Refer to the onboarding documentation provided to you by Paze. It is important that the keypair that you create NOT additionally use password protection. Those passwords cannot be shared with Spreedly, and will prevent your payments from being processed.

Store this certificate very safely. It is important to prevent others from gaining access to it. The first time you will go through this process is with the sandbox certificate. There is less risk if your sandbox certificate is compromised, but take the time to think about how you will do this safely and securely when you are ready for launch.

Input Certificate to Spreedly

Create a Certificate at Spreedly utilizing the Certificate API and your PEM from your Paze Certificate. Retain the token of the Certificate returned by the API. This will be used to decrypt the secure payment information.

Receive Client ID

EWS will issue you a client ID that will be needed when you begin to integrate the JavaScript onto your page.

Gateways

Paze can be utilized with any of the gateways that support Network Tokenization.

Checkout Flows

Paze supports several customizations that enable your custom checkout experience. It is recommended to understand and decide on the following items before starting your integration:

Prepare your front end

Paze provides the most up to date version of their SDK documentation via their portal. It is recommended to review their documentation as an aid to this guide.

You will need to add the Paze SDK and manage front end user interaction in order to offer Paze.

Initialize the SDK

Load and initialize the SDK and create an adaptor. To do this you will need your Client ID from Paze.

Before calling Initialize, Merchants must load the PazeSM SDK. The SDK creates a popup that is used to host the user interface (UI) for the SDK.

The following example shows how to load the SDK and create an adapter:

<head> 
</head> 
  <body> 
 <script 
src="https://sandbox.digitalwallet.earlywarning.com/web/resources/js/digit
alwalletsdk.js?id=<id>" type="text/javascript"> 
 </script> 
 <script>  
      let digitalWalletAdaptor = window.DIGITAL_WALLET_SDK;
  digitalWalletAdaptor.initialize({
      "client":<id>",
        "name": "<name>",
        "profileId": "<profileid>"
      }
    });
 </script>  
  </body>

Replace the id with your Client ID value in both the src and the initialization request. The Name and Profile ID are as assigned by Paze and associated to the Client ID.

The name parameter within the Client object becomes the display name within the Paze user experience. It is recommended that this field is consumer identifiable and simple.

When presenting any SDK UI, the SDK controls the seamless operation of the window as a popup.

Creating session IDs

The session ID is optional for sending the request checkout and complete requests, however, for the merchant to receive a securedPayload with payment credentials, the sessionId must be present. The sessionId is not required if requesting a card on file.

The merchant is responsible for generating the sessionId and keeping track of it.

Hereโ€™s example of how we generate a basic sessionId in JavaScript:

// Simple function to generate a session id  
const generateSessionId = (length) => {  
  const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";  
  let result = "";  
  for (let i = 0; i \< length; i++) {  
    result += chars.charAt(Math.floor(Math.random() \* chars.length));  
  }  
  return result;  
}  
// Generate a session id that is 24 characters long  
const sessionId = generateSessionId(24)

A merchant will need to keep this session id at least for the duration of the transaction.

Display the checkout button

There are two options for displaying the button: always showing a static button or dynamically generating a button. It is up to you on which option to offer.

Paze has specific brand guidelines to follow when displaying their button and logo. They can provide you with an SVG to use on your page.

Static Button

Use a static button if you want to always display Paze as a checkout option, or you do not capture the user's email address prior to showing payment options. There is no ability for users to create and add cards to Paze at this time. Consumers can refer to their bank or credit union to add a card to their Paze wallet.

Dynamic Button

If you have a user's email address, you can dynamically display Paze as a checkout option based on the user's enrollment in the system.

To dynamically display a button, create a "canCheckout" request that takes in the email address of the consumer. The SDK will respond with consumerPresent and either true or false. If true, go ahead with displaying your button. If false, do not.

// Access the input element where the user enters their email  
const pazeEmailInput = document.getElementById("paze-email");  

// Listen for input changes and check if the user can checkout with paze  
pazeEmailInput.addEventListener("change", async () => {  
  // regex to check if the email entered has a valid format  
  const emailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)\*$/;  
 
  // If the email is valid, use the canCheckout function to validate if the user can checkout with Paze  
  if (emailRegex.test(pazeEmail.value)) {  
    const canCheckout = await digitalWalletAdaptor.canCheckout({ emailAddress: pazeEmail.value });  
   
    // Make the checkout button visible if canCheckout.customerPresent is true  
    if (canCheckout.customerPresent)  checkoutButton.style.display = "block";  
   
    // Hide the checkout button otherwise  
    else checkoutButton.style.display = "none";  
  }  
});

If your customer is registered, you can call .canCheckout() with their registered email. If your customer is a guest visitor, present an email address field in the payment view so they can provide their Paze email address.

Collecting Billing and Shipping addresses

Shipping address information can be collected through Paze, or through a form controlled by the merchant. If the merchant wishes to collect the shipping address through their own form, then they should set the shippingPreference parameter of the .checkout() call to "NONE". This will suppress address related screens from the checkout experience within Paze.

Billing address is collected from Paze. By default the .checkout() response will contain the full address.

Final Confirmation or Express Pay

If the merchant sends the complete request right after the checkout request resolves, without presenting their customer a confirmation screen, then the following key-value pair should be included in the .checkout() call so the customer is notified in advance about the express payment process.

intent: โ€œEXPRESS_CHECKOUTโ€

Express Checkout Paze UI example

Express Checkout Paze UI example

On the other hand, if the customer is presented with a confirmation screen after the checkout request resolves, and then is required to take action (click) to call the .complete() function, there is no need to add the "EXPRESS_CHECKOUT" intent to the .checkout() call.

Checkout

Call the .checkout() function with the appropriate parameters depending on the operation being performed.

Invoking Checkout causes consumers to enter the Paze UI via popup.

  • If actionCode is START_FLOW
  • If the consumerโ€™s email address is not provided in the request, the consumer will be prompted to submit it within the SDKโ€™s UI.
    • Lookup is performed using the email address.
    • If the consumer is not found or is ineligible, the SDK will display an in-line error screen so the consumer knows to return to the merchantโ€™s site.
    • If the consumer is found and is eligible, the SDK will proceed normally.
  • If the consumerโ€™s email address is provided in the request, the SDK will perform a lookup before launching the UI.
    • If the consumer is not found or is ineligible, the SDK will return an error so the merchant can route them to an alternative payment method.
    • If the consumer is found and is eligible to check out, the SDK will proceed normally.
  • The SDK will render the following screens:
    • Consumer authentication
    • Card selection
    • Shipping address selection or entry (if configured in the Checkout request)
  • If actionCode is CHANGE_CARD or CHANGE_SHIPPING_ADDRESS
    • The SDK renders only the respective screens to select the card or shipping address.

Hereโ€™s an example function to start the checkout flow and how to invoke it:

const checkout = async () => {  
  const checkoutPlayload = {  
    emailAddress: "[[email protected]](mailto:[email protected])",  
    actionCode: "START_FLOW",  
    sessionId,  
    transactionValue: {  
      transactionCurrencyCode: orderCurrency,  
      transactionAmount: orderTotal,  
    }  
  };  
 
  // Launch checkout experience within Paze popup  
  await digitalWalletAdaptor.checkout(checkoutPlayload);  
  
  // Alternative, do something with the response (like grabbing the address, or other data)  
  // const response = await digitalWalletAdaptor.checkout(checkoutParams);  
  // const checkoutResponseToken = response.checkoutResponse;  
  // const decodedResponse = decodeToken(checkoutResponseToken);  
  // doSomethingWithResponse(decodedResponse);  
};  

// Get the checkout button  
const checkoutButton = document.getElementById("paze-checkout-button");  

// Listen for a click on the checkout button  
checkoutButton.addEventListener("click", async () => {  
  // call the checkout and wait for it to resolve  
  await checkout();  
});

Expected raw checkout response example:

{  
    "result": "COMPLETE",  
    "checkoutResponse": "eyJhdWQiOiJodHRwOi8vMTI3LjAuMC4xOjQwMDAiLCJraWQiOiI4MzYyODY2ZC1kODE2LTRiOGMtYWRkMy0yZDEwOTQ2NDc4NWMiLCJpc3MiOiJodHRwczovL3NhbmRib3guZGlnaXRhbHdhbGxldC5lYXJseXdhcm5pbmcuY29tIiwidHlwIjoiSldUIiwiZXhwIjoxNzE0MDU5NjAwLCJpYXQiOjE3MTM4ODY4MDAsImFsZyI6IlJTMjU2IiwianRpIjoiMGZlMGI1NjgtOWQ1NC00MGE2LWE2ODgtNzQ5MDRhZDA1MDU1In0.eyJzZXNzaW9uSWQiOiJmYzU5ZjFiYmMyNWVhZWE2NTJhNTE1MjFiNWZkN2Q0YiIsImNvbnN1bWVyIjp7ImZpcnN0TmFtZSI6IlNwcmVlZGx5IiwibGFzdE5hbWUiOiJJbnRlZ3JhdGlvbnMiLCJmdWxsTmFtZSI6IkludGVncmF0aW9ucyIsImVtYWlsQWRkcmVzcyI6ImludGVncmF0aW9uc0BzcHJlZWRseS5jb20iLCJtb2JpbGVOdW1iZXIiOnsiY291bnRyeUNvZGUiOiIxIiwicGhvbmVOdW1iZXIiOiI5MTAzMTc5NTA2In0sImNvdW50cnlDb2RlIjoiVVMiLCJsYW5ndWFnZUNvZGUiOiJFTiJ9LCJtYXNrZWRDYXJkIjp7ImRpZ2l0YWxDYXJkSWQiOiJjNTI3YWM2ZS02NGU5LTQyMzEtYWRjYy1iODIxMmM1YzFjNGYiLCJwYW5MYXN0Rm91ciI6IjE5NTgiLCJwYXltZW50QWNjb3VudFJlZmVyZW5jZSI6IlYwMDEwMDEzMDIzMTUzNTk3OTczNDE4NDI4MDc4IiwicGFuRXhwaXJhdGlvbk1vbnRoIjoiMDUiLCJwYW5FeHBpcmF0aW9uWWVhciI6IjIwMzIiLCJwYXltZW50Q2FyZERlc2NyaXB0b3IiOiJUZXN0IFNob3J0IDIiLCJkaWdpdGFsQ2FyZERhdGEiOnsiYXJ0VXJpIjoiaHR0cHM6Ly9zYW5kYm94LmFzc2V0cy52aW1zLnZpc2EuY29tL3ZpbXMvY2FyZGFydC9kNjMzMzBhMDE4NGQ0ZDdmOTEwNWUwN2VhZGQ5YTE5Y19pbWFnZUMifSwiYmlsbGluZ0FkZHJlc3MiOnsibGluZTEiOiI4MTcgRnJlZGVyaWMgTmVjayIsImNpdHkiOiJBc2hldmlsbGUiLCJzdGF0ZSI6Ik1OIiwiY291bnRyeUNvZGUiOiJVUyIsInppcCI6IjY3MDYzIn0sInBheW1lbnRDYXJkVHlwZSI6IkRFQklUIiwicGF5bWVudENhcmRCcmFuZCI6IlZJU0EiLCJwYXltZW50Q2FyZE5ldHdvcmsiOiJWSVNBIn0sInNoaXBwaW5nQWRkcmVzcyI6eyJsaW5lMSI6IjgxNyBGcmVkZXJpYyBOZWNrIiwiY2l0eSI6IkFzaGV2aWxsZSIsInN0YXRlIjoiTU4iLCJ6aXAiOiI2NzA2MyIsImNvdW50cnlDb2RlIjoiVVMiLCJkZWxpdmVyeUNvbnRhY3REZXRhaWxzIjp7ImNvbnRhY3RGdWxsTmFtZSI6IlNwcmVlZGx5IEludGVncmF0aW9ucyIsImNvbnRhY3RQaG9uZU51bWJlciI6eyJjb3VudHJ5Q29kZSI6IjEiLCJwaG9uZU51bWJlciI6IjkxMDMxNzk1MDYifX19fQ.I7sWB1QuGuTfsrNZO2nT3tzxH9-36oJMc-hLrPJ1W75qfknZ-9IguFht6s_BYqldFid3o-ZTdeOgz7RHNuk_mHtcc1pq592nILqyr1WiYcZctJc7vk1QEhBJbT9Hy4PylpVHWAm1Zvsp5vnlln2V4k0Ro1uudBqEiVhWJkwc-byIHAgb0_YhwC05cE4qbeMUE_JfBRlmINJoI8V0z7nLUVnNd-0LkJwnre8KQsB6N6eZClcmLIsI66E15CwtJaDAS-2lbz3GBxpU9ViQQUmaOhFFtfBIwCNf2gygw5LELEqIL-ok3M-GF6UADVEgqapNM_qTkBHwEDFSFmAa7ocQoQ"  
}

Function to decode the JWT received from the checkout call checkoutResponse:

const decodeToken = (token) => JSON.parse(atob(token.split('.')[1]));  

decodeToken(checkoutResponse)

Expected JWT decoded response example:

{  
    "sessionId": "fc59f1bbc25eaea652a51521b5fd7d4b",  
    "consumer": {  
        "firstName": "Spreedly",  
        "lastName": "Integrations",  
        "fullName": "Integrations",  
        "emailAddress": "[[email protected]](mailto:[email protected])",  
        "mobileNumber": {  
            "countryCode": "1",  
            "phoneNumber": "910179506"  
        },  
        "countryCode": "US",  
        "languageCode": "EN"  
    },  
    "maskedCard": {  
        "digitalCardId": "c527ac6e-64e9-4231-adcc-b8212c5c1c4f",  
        "panLastFour": "1958",  
        "paymentAccountReference": "V0010013023153597973418428078",  
        "panExpirationMonth": "05",  
        "panExpirationYear": "2032",  
        "paymentCardDescriptor": "Test Short 2",  
        "digitalCardData": {  
            "artUri": "<https://sandbox.assets.vims.visa.com/vims/cardart/d63330a0184d4d7f9105e07eadd9a19c_imageC">  
        },  
        "billingAddress": {  
            "line1": "817 Frederic Neck",  
            "city": "Asheville",  
            "state": "MN",  
            "countryCode": "US",  
            "zip": "67063"  
        },  
        "paymentCardType": "DEBIT",  
        "paymentCardBrand": "VISA",  
        "paymentCardNetwork": "VISA"  
    },  
    "shippingAddress": {  
        "line1": "817 Frederic Neck",  
        "city": "Asheville",  
        "state": "MN",  
        "zip": "67063",  
        "countryCode": "US",  
        "deliveryContactDetails": {  
            "contactFullName": "Spreedly Integrations",  
            "contactPhoneNumber": {  
                "countryCode": "1",  
                "phoneNumber": "9103179506"  
            }  
        }  
    }  
},  
{  
    "aud": "<http://127.0.0.1:4000">,  
    "kid": "8362866d-d816-4b8c-add3-2d109464785c",  
    "iss": "<https://sandbox.digitalwallet.earlywarning.com">,  
    "typ": "JWT",  
    "exp": 1714059600,  
    "iat": 1713886800,  
    "alg": "RS256",  
    "jti": "0fe0b568-9d54-40a6-a688-74904ad05055"  
}

Scenarios and Error Handling

ScenarioHandling
After selection of card from Paze wallet, masked card is returned in checkout response to summarize Merchant page; Customer wants to change cardReinvoke checkout API with actionCode CHANGE_CARD value
Session timeout,
failed authentication or
customer exists
checkout response โ€œresultโ€ = INCOMPLETE, return customer to Merchant checkout page
After selected shipping address from Paze wallet and continues; Customer wants to change address
(when there is no option to edit on Merchant page)
Reinvoke checkout API with actionCode CHANGE_SHIPPING_ADDRESS value

Completing the transaction with Paze

Call .complete() with the one of the following payload objects depending on the operation(s) being performed. If a purchase is performed, the return will be a JWT token which upon decoding will reveal the payloadId, sessionId and securedPayload (which contains the payment data required to process the transaction).

// Payload to perform ONLY PURCHASE  
const purchaseCompletePlayload = {  
  sessionId: sessionId,  
  transactionType: "PURCHASE",  
  transactionOptions: {  
    merchantCategoryCode: "12345",  
    billingPreference: "ALL",  
    payloadTypeIndicator: "PAYMENT",  
  },  
  transactionValue: {  
    transactionCurrencyCode: orderCurrency,  
    transactionAmount: orderTotal,  
  },  
};  

// Payload to perform PURCHASE AND keep CARD ON FILE  
const bothCompletePlayload = {  
  sessionId: sessionId,  
  transactionType: "BOTH",  
  transactionOptions: {  
    merchantCategoryCode: "12345",  
    billingPreference: "ALL",  
    payloadTypeIndicator: "PAYMENT",  
  },  
  transactionValue: {  
    transactionCurrencyCode: orderCurrency,  
    transactionAmount: orderTotal,  
  },  
};  

// Payload to ONLY keep CARD ON FILE  
const keepCardOnFileCompletePlayload = {  
  sessionId: sessionId,  
  transactionType: "CARD_ON_FILE",  
  transactionOptions: {  
    merchantCategoryCode: "12345",  
    billingPreference: "ALL",  
    payloadTypeIndicator: "PAYMENT",  
  },  
  transactionValue: {  
    transactionCurrencyCode: orderCurrency,  
    transactionAmount: orderTotal,  
  },  
};

Example of how to complete the payment with Paze:

const completePayment = async () => {  
  const purchaseCompletePayload = {  
    sessionId: <sessionId>,  
    transactionType: "PURCHASE",  
    transactionOptions: {  
      merchantCategoryCode: "12345",  
      billingPreference: "ALL",  
      payloadTypeIndicator: "PAYMENT",  
    },  
    transactionValue: {  
      transactionCurrencyCode: <orderCurrency>,  
      transactionAmount: <orderTotal>,  
    },  
  };  

  // call .complete(), decode the response and return it  
  const response = await digitalWalletAdaptor.complete(purchaseCompletePlyload);  
  return decodeToken(response.completeResponse);  
};

Expected .complete() raw response example:

{  
    "completeResponse": "eyJhdWQiOiJodHRwOi8vMTI3LjAuMC4xOjQwMDAiLCJraWQiOiI4MzYyODY2ZC1kODE2LTRiOGMtYWRkMy0yZDEwOTQ2NDc4NWMiLCJpc3MiOiJodHRwczovL3NhbmRib3guZGlnaXRhbHdhbGxldC5lYXJseXdhcm5pbmcuY29tIiwidHlwIjoiSldUIiwiZXhwIjoxNzE0MDU5NjA2LCJpYXQiOjE3MTM4ODY4MDYsImFsZyI6IlJTMjU2IiwianRpIjoiNUM4MUE3NkVFODAwZGZkZWQxNzctZWEyYi1mNDk5LTA3MWYtMWY3ZDU1NWE2ZDAxIn0.eyJwYXlsb2FkSWQiOiJkZmRlZDE3Ny1lYTJiLWY0OTktMDcxZi0xZjdkNTU1YTZkMDEiLCJzZXNzaW9uSWQiOiJmYzU5ZjFiYmMyNWVhZWE2NTJhNTE1MjFiNWZkN2Q0YiIsInNlY3VyZWRQYXlsb2FkIjoiZXlKaGRXUWlPaUpvZEhSd09pOHZNVEkzTGpBdU1DNHhPalF3TURBaUxDSnJhV1FpT2lKemNISmxaV1JzZVY5elluaGZhMlY1SWl3aWFYTnpJam9pYUhSMGNITTZMeTl6WVc1a1ltOTRMbVJwWjJsMFlXeDNZV3hzWlhRdVpXRnliSGwzWVhKdWFXNW5MbU52YlNJc0ltTjBlU0k2SWtwWFZDSXNJblI1Y0NJNklrcFhWQ0lzSW1WdVl5STZJa0V5TlRaSFEwMGlMQ0psZUhBaU9qRTNNVFF3TlRrMk1EWXNJbWxoZENJNk1UY3hNemc0Tmpnd05pd2lZV3huSWpvaVVsTkJMVTlCUlZBdE1qVTJJaXdpYW5ScElqb2laR1prWldReE56Y3RaV0V5WWkxbU5EazVMVEEzTVdZdE1XWTNaRFUxTldFMlpEQXhJbjAualp2Q0FBSkZQM0FzN3pPOG90U0tjY1NNRWFPUWRmM25PR2VfaXluck9renhGWmN6cjYxWmhESDQwWDJUUjVPVUlnTFU2U1JnQU9EOU42N0xuMVJUOG41OVNrRFNBTnhnRnVtZkVXZmIxVm5EYzV0N2FKMmltcVJ6NFR2WmpLanBTeGYtaTNZOTVqdkgxSGlqenJ0U3lQVGJYUlI3NTlLMXFzVHZILXlHUXp0WGY3Z1Vjd2VpeEQyZjZYVmNkQlJENWQzY1BvdU9GdW1Oak9MdEVCZjlfcEhaNW9lMU84Vm83VVI2MkRBYVYtZHhRZ2lVZnlfYVQyOFFaSDNfbkRVeFZsaHpYVXhHUXl1YmYxckl5N1liYWZJS1gwWmxfNmVPS2w1bVRZNl9IbjJRTjhSTWFnZ0p1TXJXTlJ5S3B2R2VRU1Y2SXR1NGtSWTdtQmg4T2JhdVJRLkhHdWstUVJHYUVjWHZOU2YuQTFEcjhSYUItT2tKd2dQaERYTzhEZEpNWnJYdFNEYlgtWWpSZ0pRRG0yVkpvVlB5UXVCelBqVWRSWUxCY21yeHdVaEJFWVVLcGRJdEpOMVduV1hhNDk5MF80LVZxYUdCY3NtU2ZvRDZOYXd0cUpDczMwSTk3QnljelotV29BQ3pqWm5jMEVPZ1dMODdmZzhpWk42cFZGdVMzOC02eGJhdlNRcDNHajRZNkc1azdiQ1B3b0JWTkRYd3llandfRjBkRGp6Wk00SU10ZWdxckJERkpEQmE5dGpPNFo0RnhXcWU1eVF1cWdlM1diTXFmZC1lUjM2b1BBQ25ISHRrQkNyUFlrdEdOeE1vOFRlYWdQZkNtWnRXeGR0TGZwVXhhNFlWbDR3OGNjbVFCZmgyWWJQMTJoYmY0Y0pTbi1BWU5VclNzU1UzQ1pTUzJwcXg3T0pISmVXY3RVcVBrYzlIOVI1dFpFZGx4bEdaRzFMcF9VNnVla0diSzZnVWx1M1IwSHFZRzBFZDFCNFozS3RzQWhkU0NGQW5MMzdGOHVxYW9KMEphd2dPbW1nYmtlZS1oSFdOa1UteV80c1lzQXhDNTNJWVlQdktQVnlNSGxYdm5pS0xveVZFN093d1pEZ2oxN3hINE9wc0h1a1U1UFI4bTNHbHk3Ny1wYlVRWVhnRjE5dnJZRFp4RjJQdmRuMG1kZUZ4WVA3cmctLUVCMG9kdzBnTVo5MGlENk00T2NZV0xCMXN0dFVhaTh1WUR3SzVzX3ZDU1MzejJDR1dzQWp0UE9KY1RfRG9HQm8zd1FLQ1RPcFRWcE9kcDJXeFZMQjd3STY5NG00VFFwNnZMcDlPOHc5OWxydDZEU1Q2bV9vQTdiRXIwTzJHN3hoWWtCTllTRWVIRjFRTk1mRnJwTUxpTHZ6TVR2eVB4SUIySzhOTUhmTlNZU19RWmtpRkw4bmk0OVhhQTBFU25Pb2xDalFKWlZKMlpSRUNDOFN4T01fNk5HZzU1WmE3NEZ0RWY0WWdlQnJNYTJMM3B3ek10M0FtMF82SlEzNEpyalZkLXlYMWtlVWZVeXJTN3JFTFpkM2lEeHcxVXZQOEhlbWt3TjFUaVg0Q3BCaGx1dndxZkxfYzlXeGR2c0ZFdUFjeUZIRVN4Um5mRG5LLTkzTkZPeEctMEFMOGZqRktVSnBVZXRPb1B5X25KTDJkc1E4ZzVqVGxkQTk5NHRFZy1NYzVrRE1sWkI3X0d0bndqZkV4V3U0di10cHNWZWhQc3pKV0RnNUdFZ1lRa09GSUtVME1MZndBc2xoU3Y5WmVuSzBTM2w4RWs0Tk9YejBhU0d3bXl0LUxkR0pycWZkN2pJLS1KbDlrNWZKXzFxazJiRlJoMVVVUmZoQlBncU5vamtHV3U2ZU5fV2JkRE16VGktcDdBME5HaTJPbjhMYmJHZzJ5YkxKRlFiNGY0UmNpWWRvYUpGdEhZSDlhRFRKWUN6RkI4aFNSQkVmSnJzTTlyVm1seG5VaUY3bnpHYnZaS1plLUMyMS1DbFliVjZUUHppV1UwQmJFR1BPY3FXQ3NNLVFBTWJXR1VFLVdKVVlIU25zR1hSUms5elVlWkJwR04yNVhXSS1Bc1dlQ3B2b0xiN1p6bHJ2alBweUdNT3pxU3R5clpNVjM1aHNkM21VRGdMdDgwbGRQdnBXVFViVWVhNXcxaE1NV292Tks0Rl9hMndWcUZVM3ZVc3hzcjRpMmNRc3JBY2VoRzNpVVNIYURoUURtZHprZFMxYjRIZkhGQU9mUzl2cUp2X3VNTHd5OHJSVjczY09iUWtwcXlFaVBPT1ZUWGJ2VnNuUzdNZE9nUlZydlFmbk5VdVVWWnh6TmREVlB6MTNucF9PMHd6RTh0RDhLb3JQZlVnUWNMSXJZZDZFNWtScldtbDcwR3k2YkNIcjNtaDRCR2gtWlhYZjA1S2dhUWJhcFZWU3hSVEp3RTJ0MHRvSzJCQ255QUo5Y19RWkYyZEhyZVVmTUlNRTNpLUlDS1BxM0xra2NwWGpLdC1YeHFkRzJJNm51RzlKYkNRVDhxa2FPZ3pkWUVnX0pick1NOEJpMFdwTWo0N3JUSjhfaXhpcEI3WDlUcnVDaXR3MTFPZTVZay1WRUlvbmxVOUxUMFY2MEpibEFRYWVhQ2xzZ1RfZjFnb1JoVjJfOERDOXNDM3p6LXNGRHdBM2xaOXhFbWptUW5RaGFTaVZmMEFjbTVHeVVMakFBTzFTSk5ma01ITXBoV3E4VnBvc1hQVDE4WVQ3N1daYnFGUlRnUWNvQjcybF9La3hGMWFfLUtjYmJKWVF5MHg0bTNDTkYxM2swZGQ2eTFfZV9XZVN3dnUtYWRHc3hnUXJBdlhvMy15azFBS2ktZnJFQWg1dVhickp4YzBQWUVENWlxbW4yZ3JCUDNsdjNmV2xoaDJGd1Z0Nl81QWloanVmbHRfT2VaUG84cklaR1RqcnVCY25sWEZGSjR4NGpJSWxMNndJRmowcU1xOHR1NGhOcFNCSTNEZGkwZFlQNGp5RjFRSHI0LXY1YTFWdUMzWXlHOGN0SW5aeVp3ZkxRR0V2SEREcWh2MUt3YjVmRGRNei1mZ3lzRHpOOFYxcldtYWlKeTdmY3cyTUdFSklkREt6MUJaa0tDSUl5LXR3WkNsTEhHN1lRQ2RmR1VGelR0X0RfMDR6Rnhqb2R4aDVDbExqSzFMQ01BQWtUa0F6VDV5cndCRWE1QV9SSDBOdDgwN083c3NWV1hMV29CWFFIWjRwVFRJekhmcUlpcFdrWEFoY0Z3X2ZMVG0yXzhPOVFGZVBvRE9jUVp1eEVocDg1aUhoZHZveE1kWWlpeWRrdDNsSkZHbExFUG04ajBPUDBVSUphMElqMFlhZUl2UkwtQzd0LXV4Z2RNV0xTVjBhNXcxZFdxRXVaS013Nm5GTTExcGdVSkR5XzdlbUFlU1FWTlN5WjJPc0xsVFpIM2FpSi5yTlRWYVVRcWcwZkg0d1hiSXVBbDVBIn0.BdSkppfcsgAEeBLgU4bEGZNUZrarasdQbH2veI2NYibnrpPErzJXoOpJqmXKD1gugd1iY9suvyNMZNpajCViaec2b7U1Kvd2dWXm0Vi6C6qcMoldteR206nCSLXIBzvgk6NDP50UjtFjAjdlju4WfSF6z2pWdXRnlJEeX580436Dk4tYVqw9M_9q0CxKsEzyp_7DIe4yhP3jkI9gV2_bFeQUY9b7aVjepmYThfWUUz7lPO2Lg6jstgR0O9bJhg4JJGlBqwJjgonScu3XsmuohLO2buTAUUGatc-dz_bS9RfYVFlxgdGZN6Po8ksyM-vXophjJU_7niqONzfiHURfFw"  
}

Expected .complete() response JWT decoded example:

[  
    {  
        "payloadId": "dfded177-ea2b-f499-071f-1f7d555a6d01",  
        "sessionId": "fc59f1bbc25eaea652a51521b5fd7d4b",  
        "securedPayload": "eyJhdWQiOiJodHRwOi8vMTI3LjAuMC4xOjQwMDAiLCJraWQiOiJzcHJlZWRseV9zYnhfa2V5IiwiaXNzIjoiaHR0cHM6Ly9zYW5kYm94LmRpZ2l0YWx3YWxsZXQuZWFybHl3YXJuaW5nLmNvbSIsImN0eSI6IkpXVCIsInR5cCI6IkpXVCIsImVuYyI6IkEyNTZHQ00iLCJleHAiOjE3MTQwNTk2MDYsImlhdCI6MTcxMzg4NjgwNiwiYWxnIjoiUlNBLU9BRVAtMjU2IiwianRpIjoiZGZkZWQxNzctZWEyYi1mNDk5LTA3MWYtMWY3ZDU1NWE2ZDAxIn0.jZvCAAJFP3As7zO8otSKccSMEaOQdf3nOGe_iynrOkzxFZczr61ZhDH40X2TR5OUIgLU6SRgAOD9N67Ln1RT8n59SkDSANxgFumfEWfb1VnDc5t7aJ2imqRz4TvZjKjpSxf-i3Y95jvH1HijzrtSyPTbXRR759K1qsTvH-yGQztXf7gUcweixD2f6XVcdBRD5d3cPouOFumNjOLtEBf9_pHZ5oe1O8Vo7UR62DAaV-dxQgiUfy_aT28QZH3_nDUxVlhzXUxGQyubf1rIy7YbafIKX0Zl_6eOKl5mTY6_Hn2QN8RMaggJuMrWNRyKpvGeQSV6Itu4kRY7mBh8ObauRQ.HGuk-QRGaEcXvNSf.A1Dr8RaB-OkJwgPhDXO8DdJMZrXtSDbX-YjRgJQDm2VJoVPyQuBzPjUdRYLBcmrxwUhBEYUKpdItJN1WnWXa4990_4-VqaGBcsmSfoD6NawtqJCs30I97ByczZ-WoACzjZnc0EOgWL87fg8iZN6pVFuS38-6xbavSQp3Gj4Y6G5k7bCPwoBVNDXwyejw_F0dDjzZM4IMtegqrBDFJDBa9tjO4Z4FxWqe5yQuqge3WbMqfd-eR36oPACnHHtkBCrPYktGNxMo8TeagPfCmZtWxdtLfpUxa4YVl4w8ccmQBfh2YbP12hbf4cJSn-AYNUrSsSU3CZSS2pqx7OJHJeWctUqPkc9H9R5tZEdlxlGZG1Lp_U6uekGbK6gUlu3R0HqYG0Ed1B4Z3KtsAhdSCFAnL37F8uqaoJ0JawgOmmgbkee-hHWNkU-y_4sYsAxC53IYYPvKPVyMHlXvniKLoyVE7OwwZDgj17xH4OpsHukU5PR8m3Gly77-pbUQYXgF19vrYDZxF2Pvdn0mdeFxYP7rg--EB0odw0gMZ90iD6M4OcYWLB1sttUai8uYDwK5s_vCSS3z2CGWsAjtPOJcT_DoGBo3wQKCTOpTVpOdp2WxVLB7wI694m4TQp6vLp9O8w99lrt6DST6m_oA7bEr0O2G7xhYkBNYSEeHF1QNMfFrpMLiLvzMTvyPxIB2K8NMHfNSYS_QZkiFL8ni49XaA0ESnOolCjQJZVJ2ZRECC8SxOM_6NGg55Za74FtEf4YgeBrMa2L3pwzMt3Am0_6JQ34JrjVd-yX1keUfUyrS7rELZd3iDxw1UvP8HemkwN1TiX4CpBhluvwqfL_c9WxdvsFEuAcyFHESxRnfDnK-93NFOxG-0AL8fjFKUJpUetOoPy_nJL2dsQ8g5jTldA994tEg-Mc5kDMlZB7_GtnwjfExWu4v-tpsVehPszJWDg5GEgYQkOFIKU0MLfwAslhSv9ZenK0S3l8Ek4NOXz0aSGwmyt-LdGJrqfd7jI--Jl9k5fJ_1qk2bFRh1UURfhBPgqNojkGWu6eN_WbdDMzTi-p7A0NGi2On8LbbGg2ybLJFQb4f4RciYdoaJFtHYH9aDTJYCzFB8hSRBEfJrsM9rVmlxnUiF7nzGbvZKZe-C21-ClYbV6TPziWU0BbEGPOcqWCsM-QAMbWGUE-WJUYHSnsGXRRk9zUeZBpGN25XWI-AsWeCpvoLb7ZzlrvjPpyGMOzqStyrZMV35hsd3mUDgLt80ldPvpWTUbUea5w1hMMWovNK4F_a2wVqFU3vUsxsr4i2cQsrAcehG3iUSHaDhQDmdzkdS1b4HfHFAOfS9vqJv_uMLwy8rRV73cObQkpqyEiPOOVTXbvVsnS7MdOgRVrvQfnNUuUVZxzNdDVPz13np_O0wzE8tD8KorPfUgQcLIrYd6E5kRrWml70Gy6bCHr3mh4BGh-ZXXf05KgaQbapVVSxRTJwE2t0toK2BCnyAJ9c_QZF2dHreUfMIME3i-ICKPq3LkkcpXjKt-XxqdG2I6nuG9JbCQT8qkaOgzdYEg_JbrMM8Bi0WpMj47rTJ8_ixipB7X9TruCitw11Oe5Yk-VEIonlU9LT0V60JblAQaeaClsgT_f1goRhV2_8DC9sC3zz-sFDwA3lZ9xEmjmQnQhaSiVf0Acm5GyULjAAO1SJNfkMHMphWq8VposXPT18YT77WZbqFRTgQcoB72l_KkxF1a_-KcbbJYQy0x4m3CNF13k0dd6y1_e_WeSwvu-adGsxgQrAvXo3-yk1AKi-frEAh5uXbrJxc0PYED5iqmn2grBP3lv3fWlhh2FwVt6_5Aihjuflt_OeZPo8rIZGTjruBcnlXFFJ4x4jIIlL6wIFj0qMq8tu4hNpSBI3Ddi0dYP4jyF1QHr4-v5a1VuC3YyG8ctInZyZwfLQGEvHDDqhv1Kwb5fDdMz-fgysDzN8V1rWmaiJy7fcw2MGEJIdDKz1BZkKCIIy-twZClLHG7YQCdfGUFzTt_D_04zFxjodxh5ClLjK1LCMAAkTkAzT5yrwBEa5A_RH0Nt807O7ssVWXLWoBXQHZ4pTTIzHfqIipWkXAhcFw_fLTm2_8O9QFePoDOcQZuxEhp85iHhdvoxMdYiiydkt3lJFGlLEPm8j0OP0UIJa0Ij0YaeIvRL-C7t-uxgdMWLSV0a5w1dWqEuZKMw6nFM11pgUJDy_7emAeSQVNSyZ2OsLlTZH3aiJ.rNTVaUQqg0fH4wXbIuAl5A"  
    },  
    {  
        "aud": "http://127.0.0.1:4000",  
        "kid": "8362866d-d816-4b8c-add3-2d109464785c",  
        "iss": "https://sandbox.digitalwallet.earlywarning.com",  
        "typ": "JWT",  
        "exp": 1714059606,  
        "iat": 1713886806,  
        "alg": "RS256",  
        "jti": "5C81A76EE800dfded177-ea2b-f499-071f-1f7d555a6d01"  
    }  
]

Transact

You can transact with Paze on any gateway that supports Network Tokenization. Please make sure you read the Network Tokenization guide and have, if needed:

  • Network Tokenization enabled on your account
  • Network Tokenization enabled on your gateway token
  • Network Tokenization enabled with your gateway

If you are only utilizing Paze for one time payments, you do not need a TRID with Spreedly.

You will still want to include any gateway specific fields and other transaction elements that you utilize with other transactions.

Initial/One Time Checkout

Spreedly will use the payment information directly from Paze, contained in the encrypted data, to make a payment. This utilizes a Paze Network Token and Cryptogram instead of a traditional FPAN.

You will still want to include any necessary gateway indicators or parameters that you send on your other transactions.

To complete a one time checkout utilizing Paze you can either create a payment method and then transact, or transact passing in the payment method.

Create a Paze Payment Method

Endpoint: POST /v1/payment_methods.json

"payment_method": {
  "third_party_network_token": {
    "certificate_token": certificate_token,
    "shipping_address1": "shipping addres test",// Optional
    "shipping_city": "test shipping city",// Optional
    "shipping_country": "United States",// Optional
    "session_id": session_id, // Optional
    "secured_payload": secured_payload, // Required, optained from the SDK's .complete()
    "source": "Paze"
  }
}

Use this payment method token in your gateway transaction

Endpoint: POST /v1/gateways/<gateway_token>/purchase.json

Requestย  payload:

"transaction": {
  "payment_method_token": payment_method_token,
  "amount": "100",
  "currency_code": "usd"
}

Transaction

You can also include the information for creating a Paze Payment method in the same API call as a transactio

Example function to process a pass-in transaction:

const processTransaction = async ({ securedPayload, sessionId, payloadId }) => {
  const payload = {
    transaction: {
      third_party_network_token: {
        certificate_token: certificateToken,
        session_id: sessionId,
        payload_id: payloadId,
        secured_payload: securedPayload,
        source: "Paze"
      },
      "amount": Number(orderTotal),
      "currency_code": orderCurrency,
    }
  }
  fetch(`${baseURL}/v1/gateways/${gatewayToken}/purchase.json`, {
    method: 'POST',
    headers: new Headers({
      "Content-Type": "application/json",
      "Authorization": "Basic " + btoa("<env_key>:<env_secret>")
    }),
    body: JSON.stringify(payload),
  }).then(response => response.json()).then(data => {
    console.log('Spreedly payment response', data);
  });
};


// Call the function with the decoded response from the .complete() call
await processTransaction(completeResponse);

Retaining Payment Methods

๐Ÿ“˜

To retain Paze payment methods, you must be an Advanced Vault customer. Please contact your Spreedly Customer Success representative

Retaining Paze payment methods is similar to other Spreedly payment methods. If you are planning on retaining payment methods, Spreedly recommends utilizing our Stored Credentials framework during transactions.

To retain as part of a transaction include "retain_on_success": true and "provision_network_token": true with your request. This is Spreedly's recommended flow for Paze, as the first payment will then use the Paze network token and cryptogram.

To retain when creating a payment method, include "retained": true and "provision_network_token": true.

When these payment methods are retained in the Vault, Spreedly performs a "swap" to attain a network token utilizing your merchant identifier (TRID). This Network Token is then availble for future use with Spreedly. Future transactions that utilize this network token can not fall back to PAN, as no PAN will exist.

Returning Users

If you have a customer initiated transaction, you can either choose to send them back through the Paze SDK user experience, or utilize the card on file token that you have with Spreedly.

If you are transacting with a stored Paze payment method token, include the parameter "attempt_network_token":true in your request.

Here is an example of a Purchase request with a retained payment method:

{
    "transaction": {
        "amount": "1000",
        "currency_code": "USD",
        "payment_method_token": payment_method_token,
        "attempt_network_token":true
    }
}