Skip to main content

LinkPay Integration ProcessDeprecated


This section includes information around Stitch products and features that are now deprecated. Deprecated aspects of Stitch's plaform are no longer being supported or improved upon.

If you are currently using a deprecated Stitch product, please consider upgrading to one of our newer and equivalent offerings.

Integration Process Summary

  1. Get a client token.
  2. Generate the payment authorization request url.
  3. Surface the url to the user using the user authorization flow.
  4. Get a user token.
  5. Initiate a payment using a user token.
  6. When required, handle the user interaction during payment initiation.
  7. Handle the final payment initiation response from the API, and query the status and/or (recommended) subscribe to receive a webhook upon payment completion.

When integrating LinkPay, a payment authorization request represents a resource created that allows users to authorize and set up payments to a specific beneficiary.

A client token is needed to create a payment authorization request. To obtain a LinkPay client token, follow the client authentication guide, making sure to request the client_paymentauthorizationrequest scope.

Once the authorization request has been completed, you can use the authorization code to obtain a user token by following the user authentication guide. This token can be used to initiate payments at any time, using the userInitiatePayment mutation on the Stitch API. If no user interaction is required, the payment will complete instantly.

However, if an interaction such as multifactor authentication is necessary, then the user may be presented with a web interface within your application, allowing them to complete the payment after supplying the required input.

Postman Collection

The LinkPay integration process has been demonstrated in this Postman collection under the collection LinkPay. Please import and review the collection's documentation, supplying the variables where required.

Creating an Account Linking Request

Once you have obtained a client token, you are able to use it to create an account linking request. An example mutation demonstrating the creation of the account linking request is shown below.

Note that the two references provided on payer and beneficiary reflect the reference that will appear on the payer and beneficiary's statement respectively.

The payer field requires that email and contact number are provided. Additional validations may apply to the payer field based on client specific validation configuration. More information on the payer input fields can be found on the Payer page.

Retrieving a Linked Account Token

The result of the above mutation returns the authorizationRequestUrl, which is the URL that replaces the base URL used in the user authorization flow.

In order to retrieve a user token, you will need to obtain an authorization code by presenting the user with a fully built authorize URL and handling the callback.

Below is a quick look at what you would need to build and append to the URL returned by the above call. Note that the client_id and redirect_uri values would need to be replaced with your own. You can find out more on how to go about building this URL here.

Browser Requirements
  1. The LinkPay product is not supported in iFrames.
  2. For browsers and WebViews, we recommend that cookies and local storage are enabled for the best user experience.

Retrieving Bank Account Details of a Linked Account

When storing the user tokens obtained in the account linking step, you will need to also store the account information related to that token. For this you can query the paymentAuthorization on the user field.


If the user has not immediately prior completed a linking and a session is not already active, then this may trigger a login notification from the user's banking app.

If the session is not active you may receive a REAUTHORIZATION_REQUIRED response. In this case you may ask the user to login again by redirecting them to the URL in the response, as per the reauthorization guide. Alternatively, you could simply attempt to initiate a payment and handle any USER_INTERACTION_REQUIRED response, which will subsequently activate the session again.

Initiate Payment

Once you have obtained a user token, you can use the token to initiate a payment. An example query that initiates a payment can be seen below. The externalReference field will be used to correlate transaction IDs within your system with the payments initiated by Stitch, and should be a unique value on your system per transaction. If provided, this value will always be sent back with the redirect query parameters and the transaction's webhook event.

Character Limits

Please note that:

  • The payerReference field is restricted to a maximum of 12 characters.
  • The beneficiaryReference field is restricted to a maximum of 20 characters.
  • The externalReference field is restricted to a maximum of 4096 characters.

Payment Initiation Statuses

This table describes the different statuses a payment initiation might have:

Response / ErrorStatusDescription
PaymentInitiationCompletedPaymentInitiationCompletedThis is a final payment state, indicating successful movement of funds.
USER_INTERACTION_REQUIREDPaymentInitiationPendingThe bank requires the user to complete a manual action. More explanation on how to handle this here.
PAYMENT_FAILEDPaymentInitiationFailedThis is a final payment state, indicating that the payment failed for one of the reasons explained here.
PaymentInitiationExpiredPaymentInitiationExpiredThe payment has expired while awaiting user interaction. More information on payment initiation expiry can be found here.
Handling initiation updates

The payment initiation request may result in an immediate, synchronous status response. However, for final status updates (and to update other payment information, such as ID), it is strongly recommended to use webhooks. These also return the externalReference field, which can be used to identify, and query, the original payment initiation.

Handling User Interaction Required

Similar to card payments, with 3D Secure, there are instances where a payment cannot complete without user interaction. This might be because the bank requires that a multifactor challenge be completed before the payment is processed, or that the user needs to accept a prompt, such as updated terms and conditions, on their account.

In this case, the payment initiation mutation will return an error, as well as a payment URL. The user will need to be redirected to this URL in order to complete the payment. The URL returned by the API requires that a whitelisted redirect_uri is appended to it as a query string argument. An example of this response can be found below:


When using a test client, link an Absa or TymeBank test account to simulate this response.

"errors": [
"message": "Multifactor required to continue payment.",
"extensions": {
"userInteractionUrl": "",
"id": "cGF5aW5pdC8zOTkxYTMyZC02ZDgyLTQ2N2UtYWU0Ny01MzQ1MDIyYWRjNjM="
"locations": [
"line": 4,
"column": 23
"path": ["userInitiatePayment"]
"data": {
"userInitiatePayment": null

Surface URL and Handle Callback

The URL returned by the API requires that a whitelisted redirect_uri be appended to it as a query string argument. If you direct a user to this URL, they will be guided through the process of completing the payment.

For example, if your whitelist URL configuration included the URL for payment requests, you'd append the following query string to the url returned from the API: ?

Whitelisting Redirect URIs

To add or remove a URL from the whitelist, please reach out to a Stitch Engineer via the usual support channels on Slack or our Support Form

Please note that production clients will not be allowed to use unsecure redirect_uri params such as http:

Once the user completes or cancels the payment request, they'll be redirected back to the redirect_uri. The query parameters below will be passed back to the redirect_uri.

Request FieldDescriptionType
idThe unique ID of this payment request.ID
externalReferenceThe value that was provided to the externalReference field when the payment initiation request was created.String
statusThe status of how the user exited the interaction-required URL. The value will be "complete" if successful, "closed" if the user clicked close within the UI, or "failed" if something went wrong when attempting the payment.String

Either the id or externalReference can be used to query the final payment request status, and other details, from the Stitch API. These are also returned in related payment webhooks.

Safe parameter handling

The status field should not be used for any final status confirmations, or similar database operations, since an external party can tweak it. To secure yourself from attackers who can send a fake payload to your redirect or webhook endpoint, we recommend:

  1. Using webhooks as the source of truth for payment status updates, which can also be expected at the time these updates occur.
  2. Making use of signed webhooks, since you'll be able to verify the signature of each incoming webhook's request payload. This also confirms the webhook has indeed been sent from Stitch.

Using the webhooks also ensures you'll still be able to know the final status of a payment request if, for example, the request times out due to a network issue.

Using Multiple Internal Redirect URIs

For a situation where different callbacks lead to different internal URLs, you SHOULD have a single whitelisted redirect URL which can then have the logic handling the Stitch callback and redirect to the internal URLs. An overview of how to do this in NodeJS is as shown below:

const status = params.status;

switch (status) {
case "completed":
case "closed":
case "failed":

Handling Payment Failed Errors

An example of a failed payment response can be found below:

"errors": [
"message": "Payment failed because insufficient funds were available.",
"locations": [
"line": 4,
"column": 23
"path": ["userInitiatePayment"],
"extensions": {
"reason": "insufficient_funds"
"data": {
"__typename": "Mutation",
"userInitiatePayment": null
Possible Payment Errors

This table describes the reasons you may encounter within the PAYMENT_FAILED error:

bank_errorPayment failed because a bank error has occurred.
blockedPayment failed due to blocked account.
declinedPayment has been declined.
duplicate_paymentPayment failed because a duplicate payment has already occurred.
invalid_destination_accountPayment failed due to an invalid destination account.
invalid_source_accountPayment failed due to an invalid source account.
limits_exceededPayment failed due to account limits exceeded.
limits_not_metPayment failed due to payment minimum not met.
readonly_account_errorPayment failed as this account is read only.
timeoutPayment failed due to a timeout.
payment_pendingError marking payment as complete. Please contact the Stitch team if you encounter this error.
unknownPayment failed due to an unknown error.
insufficient_fundsPayment failed due to the account having insufficient funds.

Subscribing to LinkPay Webhooks

To receive a webhook upon payment completion or failure you will need to create a subscription for your client. Please note that this will always send a signed webhook for your LinkPay requests. You can read more about how to verify the signature within the webhook event in our more detailed guide here

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

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

Additional Queries and Mutations

Retrieving Payment by External Reference

If the userInitiatePayment mutation was supplied with an externalReference representing the unique identifier for the payment on your system, you can then use this reference as a filter to query the payment request back.

When a user has successfully initiated the payment, the status will be PaymentInitiationCompleted and contain details of the payer and the date it was completed.

Note that this request needs a client token with the client_paymentauthorizationrequest scope.

Retrieving Payment by Stitch ID

When a user has successfully initiated the payment, the status will be PaymentInitiationCompleted and contain details of the payer and the date it was completed.

Note that this request needs a client token with the client_paymentauthorizationrequest scope.

Expiring Pending Payment Initiations

An optional expireAt Date (ISO 8601) can be supplied in the creation of the payment initiation. This can be used to mark the payment as expired if the payment is not immediately successful, and requires user-interaction. However, if the payment multifactor authentication is already underway then the payment can still be completed by the user.

Cancelling Pending Payment Initiations

If user interaction is required or the user clicks the X on the dialog box, the payment initiation will remain in the PaymentInitiationPending state until the user completes the required interaction, the payment initiation has been cancelled or the expireAt Date has passed if expireAt was supplied in the payment initiation creation request.

Cancelling a payment initiation will result in the PaymentInitiationCancelled state and can be done by calling the clientPaymentInitiationCancel mutation, which also triggers the cancel webhook event.

Viewing all Initiated Payments

To view the collection of initiated payments, you may query the Client.paymentInitiations field on the API. This will return a paged collection of initiations, dated from most recent to oldest.

Note that this request needs a client token with the client_paymentauthorizationrequest scope.