Skip to main content

Web Application Integration Process

This integration guide pertains to applications built using web-based frameworks. Stitch provides a JavaScript client-side SDK for accepting wallet payments. Stitch also vends framework-agnostic Web and React components to support quickly adding wallet payment buttons to your interface. The component supports customisation within the brand guidelines stipulated by Apple Pay, Samsung Pay and Google Pay™.

To offer all supported wallet providers, the aforementioned configuration must be completed and the payment methods must be enabled on your Stitch client.

Client

DescriptionPackageLanguage/Framework
Stitch SDK@stitch-money/clientJavaScript
React Components@stitch-money/reactReactJS
Web Components@stitch-money/webWeb/Angular

Component Interactions

This sequence diagram outlines the high-level client and server-side component interactions for Apple Pay, Samsung Pay and Google Pay. The component interactions are generalised across providers, but note that the flows differ subtly. For example, there is no merchant verification step required for Google Pay.

sequenceDiagram autonumber participant U as User participant MFE as Merchant Client (FE) participant CSDK as Stitch SDK (FE) participant RSDK as React SDK (FE) participant MBE as Merchant Server (BE) participant S as Stitch API (/graphql) MFE->>CSDK: supportedPaymentMethods() CSDK-->>MFE: WalletType[] par Apple Pay MFE->>CSDK: onClickApplePaySessionHandler() CSDK->>MFE: onClick Event Handler and Samsung Pay MFE->>CSDK: onClickSamsungPaySessionHandler() CSDK->>MFE: onClick Event Handler and Google Pay MFE->>CSDK: onClickGooglePaySessionHandler() CSDK->>MFE: onClick Event Handler end MFE->>RSDK: Import PayWithWalletButton activate RSDK RSDK->>MFE: PayWithWalletButton Component deactivate RSDK alt Apple Pay Supported MFE->>U: Render Payment Button U-->>MFE: Tap "Pay with Apple Pay" Button MFE-->>CSDK: button.onClick() CSDK-->>MBE: POST /api/apple-pay/verify activate MBE MBE-->>S: POST validateApplePayMerchant activate S S-->>MBE: sessionData deactivate S MBE-->>CSDK: sessionData deactivate MBE CSDK->>U: Display Payment Sheet U-->>CSDK: Authorize Payment CSDK-->>MBE: POST /api/apple-pay/create activate MBE MBE-->>S: POST initiateTransaction activate S S-->>MBE: ApplePayTransaction deactivate S MBE-->>CSDK: ApplePayTransaction deactivate MBE CSDK->>U: Payment Status end alt Samsung Pay Supported MFE->>U: Render Payment Button U-->>MFE: Tap "Pay with Samsung Wallet" Button MFE-->>CSDK: button.onClick() CSDK-->>MBE: POST /api/samsung-pay/verify activate MBE MBE-->>S: POST verifySamsungPay activate S S-->>MBE: sessionData deactivate S MBE-->>CSDK: sessionData deactivate MBE CSDK->>U: Display Payment Sheet U-->>CSDK: Authorize Payment CSDK-->>MBE: POST /api/samsung-pay/create activate MBE MBE-->>S: POST initiateTransaction activate S S-->>MBE: SamsungPayTransaction deactivate S MBE-->>CSDK: SamsungPayTransaction deactivate MBE CSDK->>U: Payment Status end alt Google Pay Supported MFE->>U: Render Payment Button U-->>MFE: Tap "Google Pay" Button MFE-->>CSDK: button.onClick() CSDK->>U: Display Payment Sheet U-->>CSDK: Authorize Payment CSDK-->>MBE: POST /api/google-pay/create activate MBE MBE-->>S: POST initiateTransaction activate S S-->>MBE: GooglePayTransaction deactivate S MBE-->>CSDK: GooglePayTransaction deactivate MBE CSDK->>U: Payment Status end

Client-side Integration

SDK Integration

The integration can be sub-divided into three sections: installing the SDK, handling supported payment methods, and creating a payment button.

Installation

Run the following command to install the SDK and component package applicable to your client-side framework. The @stitch-money/web package should be used for non-React applications.

npm install @stitch-money/client @stitch-money/react

Import and initialise the SDK.

import { StitchWalletClientSdk } from '@stitch-money/client';

const stitchWalletClient = new StitchWalletClientSdk({
clientId: 'your Stitch client ID',
});

Supported Payment Methods

Call supportedPaymentMethods to fetch a list of supported wallets on the device and/or browser. The PayWithWalletButton component can be used to render a payment button for any supported wallet. The method returns an array of WalletType, where the inclusion of an enum value indicates that the provider is applicable to the device/browser.

tip

supportedPaymentMethods should be used to inform the set of payment buttons to surface to the user in your application. For example, if supportedPaymentMethods returns ["SAMSUNG_PAY", "GOOGLE_PAY"] for an Android device with a card provisioned in both the Samsung Wallet and Google Pay apps, then you may choose to display one or both payment buttons using the pre-built component.

Creating Payment Button

Define callback functions for each wallet type to verify a payment session and create a payment. Note that a verify callback is only required for Apple Pay and Samsung Pay. These callbacks must be supplied as arguments along with related payment information to the onClick handler functions contained in the SDK. See the example below for representative callback function implementations.

The create payment callback receives two arguments:

  • paymentToken: A base64-encoded token used to initiate a transaction, and
  • fingerprint: a base64-encoded string containing the user's device fingerprint.

Both of these parameters must be provided when initating the transaction via the Stitch API from your server.

Bind each PayWithWalletButton component (or wrapped web component) onclick event with the corresponding onClick handler function exported from the client-side SDK, e.g., onClickApplePaySessionHandler(...). Instantiate each handler function with the set of required and optional arguments.

Apple Pay Key Points

Both verify and createPayment callback functions are required.

The validationUrl is automatically retrieved within onClickApplePaySessionHandler once an Apple Pay web session has been requested (via user interaction with the payment button). This URL must be a domain that has been previously verified in order for validation to be successful and enable the payment process to continue.

Samsung Pay Key Points

Both verify and createPayment callback functions are required.

A callback or return URL must specified to handle the redirect after the payment has been verified by the user. When moving to this callback URL after user verification, the Samsung Pay Web checkout server adds the reference ID as a query parameter, called ref_id (i.e. https://your.callback.url?ref_id={referenceID}). For more information on consuming the reference identifier, visit the Samsung Pay developer documentation. This reference must be supplied on the server-side when creating a payment via the Stitch API.

Google Pay Key Points

Only a createPayment callback function is required.

Only information related to the display of the payment sheet is required; no billing or address information needs to be supplied.

Component Implementation

Import the PayWithWalletButton component and styles directly from the @stitch-money/react package to create the payment button.

import {
type PayWithWalletButtonProps,
PayWithWalletButton,
} from "@stitch-money/react";
import "@stitch-money/react/build/styles/css";

Sample Implementation

tip

While the following example assumes the use of React, the callback function logic is framework-agnostic and the sample code is valid for any integration.

import {
StitchWalletClientSdk,
WalletType,
type ApplePaySession,
type StitchTransaction,
} from "@stitch-money/client";
import {
PayWithWalletButton,
PayWithWalletButtonProps,
} from "@stitch-money/react";
import "@stitch-money/react/build/styles/css";
import { useCallback, useEffect, useState } from "react";
import { useRouter } from "next/router";

export interface WalletPayButtonProps {
amount: number;
reference: string;
disabled?: boolean;
}

export default function WalletPayButton({
amount,
reference,
disabled = false,
}: WalletPayButtonProps) {
const router = useRouter();
const [supportedMethods, setSupportedMethods] = useState<WalletType[]>([]);
const [selectedMethod, setSelectedMethod] = useState<WalletType | null>(null);
const stitchWalletClient = new StitchWalletClientSdk({});

useEffect(() => {
async function getSupportedPaymentMethods() {
const result = await stitchWalletClient.supportedPaymentMethods()
setSupportedMethods(result);
}
getSupportedPaymentMethods();
}, []);

const createApplePayPaymentCallback = useCallback(
async (paymentToken: unknown, fingerprint: unknown) => {
const response = await fetch(
`/api/wallet/apple-pay/create`,
{
method: "POST",
body: JSON.stringify({
paymentToken,
amount: {
quantity: amount,
currency: "ZAR",
},
externalReference: reference,
fingerprint,
}),
}
);
const transaction = (await response.json()) as StitchTransaction;
if (transaction.status === "TransactionSuccess") {
router.push("/success");
}
return { status: transaction.status };
},
[amount, router, selectedMethod]
);

const applePayVerifyCallback = useCallback(async (url: string) => {
const response = await fetch("/api/wallet/apple-pay/verify", {
method: "POST",
body: JSON.stringify({
validationUrl: url,
initiativeContext: window.location.hostname,
}),
});
const session = (await response.json()) as Promise<ApplePaySession>;
return session;
}, []);

const onClickApplePay = useCallback<
PayWithWalletButtonProps["onClick"]
>(() => {
setSelectedMethod(WalletType.ApplePay);
const applePaySessionHandler =
stitchWalletClient.onClickApplePaySessionHandler(
"ZAR",
amount,
"Stitch",
applePayVerifyCallback,
createApplePayPaymentCallback
);
try {
applePaySessionHandler();
} catch (error) {
console.error(`Error starting Apple Pay session: ${error}`);
}
}, [amount, applePayVerifyCallback, createApplePayPaymentCallback]);

if (supportedMethods.includes(WalletType.ApplePay)) {
return (
<>
<PayWithWalletButton
supportedMethods={[WalletType.ApplePay]}
onClick={onClickApplePay}
disabled={disabled}
total={`${amount}`}
/>
</>
);
}
}

Server-side Integration

The integration with the Stitch API should run on your trusted application server as calls are authenticated using your sensitive Stitch credentials. This guide describes integrating directly via the Stitch API.

The GraphQL API URL https://api.stitch.money/graphql can be used for all wallet requests (whether on test or live clients). Note that a Stitch client token with the scope transaction_initiate is required to validate wallet merchants, or initiate any wallet transactions, via the API.

Validation API

The verify SDK function encapsulates two distinct Stitch API interactions for Apple Pay and Samsung Pay - the validateApplePayMerchant and verifySamsungPay mutations. These mutations must be called in the server-side verification API routes for each wallet provider and are required before a payment can be initiated.

Note

The intitiative field in the ValidateApplePayMerchantInput input object must always be set to web.

The intitiativeContext field in the ValidateApplePayMerchantInput input object refers to the fully qualified domain name where the request is originated (web application) and must match the domain associated with Apple under the merchantIdentifier specified.

For Apple Pay, the sessionData object in the validateApplePayMerchant response must be converted to a JSON object before being returned by the server-side verify API endpoint handler.

For Samsung Pay, the merchantSession object in the verifySamsungPay response must be returned unaltered by the server-side verify API endpoint handler.

Caution

Setting the intiativeContext field to test.stitch.money returns mock session data.

Note that this session data cannot be used to verify and instantiate a client-side wallet provider session. This should be used to test server-side calls in isolation. Set this field with the verified domain when testing end-to-end transaction processing.

Transaction Initiation API

To create a wallet payment, a Stitch API initiateTransaction mutation call is required in order to initiate the payment. The mutation must be called in the server-side payment creation API routes for each wallet provider.

The input variable object must be constructed distinctly for each wallet provider to correctly replicate the interaction encapsulated by the create SDK function.

The fingerprint argument supplied to the create payment callback on the client side should be specified in the deviceInformation.fingerprint field. If this is unable to be provided, other fields within the deviceInformation object are required, including all of deviceId, ip and screenDimensions.

Caution

For Apple Pay and Google Pay payments, the payment token must be Base64-encoded. The Apple Pay payment token is a JavaScript object and is a serialised object for Google Pay.

Note

The state field contained in the response is a synchronous update on the status of a payment. Note that this status will also be returned once subscribed to updates via webhook.

Enforcing 3DS

The default configuration for Wallet transactions is for 3DS to not be enforced across transactions. However, if it is required to enforce 3DS on a per-transaction basis, this is done by specifying the requireSecure3d boolean as true within the respective payment method input, for example applePay.requireSecure3d. These are shown in the Variables of the example requests, below:

3DS Configuration Requirement

The requireSecure3d parameter should only be specified if your client is configured to allow you to control performing 3DS on payments. Including this parameter without proper configuration will result in an invalid configuration error. Please reach out to Stitch if you would like to enable this feature.

Handling Transaction Responses

Default Transactions

In the default setup, with 3DS not enforced on a transaction, the state field contained in the response is a synchronous update on the status of a payment. This will either be TransactionSuccess or TransactionFailure (with a corresponding reason). Note that this status will also be returned as a webhook update, when subscribed to transaction webhooks.

3DS-Enforced Transactions

Should 3DS have been enforced on a transaction (whether dynamically, based on agreed-upon configuration with Stitch, or per-transaction as described above), a transaction initiation response will return a TransactionPending status, as well as an interactionUrl.

The user must visit this URL, after appending a redirect_uri query parameter. This will guide the user through the required 3DS interaction to complete their transaction.

As an example, if you choose to redirect your user to the whitelisted URL https://example.com/payment, you'd append the following additional query string to the url returned from the API: ?redirect_uri=https%3A%2F%2Fexample.com%2Fpayment. The full URL you would expose to the user should look similar to the following:

https://3ds.stitch.money/02fa5c7f-3aea-4545-b4e9-5af7e128ff47?redirect_uri=https%3A%2F%2Fexample.payment
danger

The URL specified as the redirect_uri must be secure i.e. an HTTPS URL.

Once the user has successfully completed the interaction and the payment has been processed, they will be redirected back to your specified redirect_uri with the following query parameters.

ParameterDescription
transactionIdThe payment's Stitch ID
flowThe 3DS interaction type i.e. challenge or frictionless
externalReferenceThe payment's external reference
statusThe payment's final status i.e. TransactionSuccess or TransactionFailure
statusReasonThe optional reason for the payment's status

You will also receive a corresponding transaction webhook to confirm the status of the transaction.

Transaction Statuses

The table below describes the different statuses of a wallet payment:

StatusDescription
TransactionPendingA payment is initialised and awaiting user authentication. If an interactionUrl is returned, the user should be directed to this for the transaction to proceed.
TransactionFailureA payment authorised by a user but unsuccessful and the requested funds were not captured.
TransactionSuccessA payment has been successfully made and the requested funds were captured.

Failure Reasons

The TransactionFailure status indicates that the wallet transaction failed to be initiated, and includes a reason explaining the cause. Potential failure reasons are detailed below:

ReasonDescription
authorizationFailedThe transaction was declined or blocked.
authorizationNotFinalisedThe transaction could not be processed by the acquirer.
blockedByFraudChecksThe transaction was blocked due to fraud checks.
downstreamProviderErrorThe transaction could not be processed due to downstream error.
exceedsCardWithdrawalLimitThe transaction was declined due to withdrawal limits exceeded.
insufficientFundsThe transaction was declined due to insufficient funds.
internalServerErrorThe transaction could not be processed due to a server error.
invalidCardErrorThe transaction was declined due to an expired card.
invalidConfigurationErrorThe client has invalid or missing configuration.
invalidTransactionErrorThe authorised payment amount (for the payment token) does not match the transaction input amount.
secure3dDeclinedThe user has declined 3DS authentication.
secure3dLookupFailed3DS authentication attempt could not be initiated.
secure3dNotCompletedThe user has not completed 3DS authentication.
tokenDecryptionErrorThe payment token could not be decrypted.

Querying Transactions

Transaction by ID

For implementing redundancy checks and logic, it is possible to query transaction statuses and details over the Stitch GraphQL API. Note that querying with the Stitch-provided id is the most performant, and the recommended approach.

Transaction by External Reference

Alternatively, querying by an externalReference is possible, and may be done with a filtering query, as follows:

note

When including this filter, the specific type of wallet transaction is required together with the external reference. As an example, the ApplePayTransaction query is shown above for Apple Pay transactions.

Webhook Subscriptions

Wallet payments require that you subscribe to transaction webhooks to receive asynchronous updates on transaction status changes.

If the subscription is successfully created, the body returned by the request will look similar to the sample in the Example Response tab in the widget above.

The webhook will contain important information regarding the transaction, including the selected wallet provider, the transaction retrieval reference number (RRN) (used for reconcilliation), external reference, and nonce.

For more information on receiving webhook events, listing active webhook subscriptions, unsubscribing from webhooks and validating signed webhook subscriptions, please visit the Webhooks page.

Webhook Statuses

When subscribed to the transaction webhook filter type, webhook updates will be sent whenever a transaction is updated to either of the following statuses:

  • TransactionSuccess
  • TransactionFailure

Testing Payment Initiation

To test payment initiation, you may use any device supported by the wallet providers applicable to your selected integration. See the Google Pay integration checklist for a more detailed description of recommended testing. Note that not all test cases/paths are applicable to the gateway integration.

Note
  • Payment initiation testing only applies to Stitch test clients.
  • A real and valid credit/debit card must be added to either the Apple, Samsung and/or Google Wallet application.
  • No funds will be captured when completing a payment with a real card and a transaction initiated by a test client.

Test Device Tokens

To simulate transaction initiation requests on test clients, you can specify J2V4YW1wbGVQYXltZW50TWV0aG9kVG9rZW4n as the paymentToken to bypass token decryption and validation that would normally be performed on a real token.

Test Cards

Testing the integration on a real device may require linking a test card to that device. For each wallet method this approach is distinct.

Apple provides a number of test cards that can be added to an Apple Wallet. These require registering a sandbox account and signing into a test device with that account. See Apple's Developer Sandbox Testing page for more details.

Simulating Transaction Statuses

For testing purposes, specific amounts can be used to simulate different scenarios when using a test client. The table below shows the mapping between amounts and transaction statuses:

AmountStatusReason
1.01FAILUREinsufficientFunds
4.04FAILUREauthorizationFailed
OtherSUCCESS-