Skip to main content

LinkPay Integration Process

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. Handle the required user interaction during payment initiation
  7. Handle the final payment initiation response from the API, and query the status and/or optionally 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. 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.

Retrieving a Linked Account Token

The result of the above mutation returns the authorizationRequestUrl, which is the URL that replaces the base https://secure.stitch.money/connect/authorize 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.

?client_id=YOUR_CLIENT_ID_HERE&scope=openid%20transactions%20accounts%20balances%20accountholders%20paymentinitiationrequest%20offline_access&response_type=code&redirect_uri=http://localhost:8080/return&state=J_Ug3dCQJG61Tt2Sejt3TY5ExgqemTXpEFhyFGapXwA&nonce=fim8Mwz0yHE85NOfgMD_sk3MdKzq2vQ_QnC0KUxIGT4&code_challenge=QO6cTsxK-_FWDrJ9xgg1fvTzsgKBcGZWHLhddFoc1tU&code_challenge_method=S256

Retrieving Data 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.

Note

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.

To obtain identity information about the user that has just linked their account and verify it against your own user KYC information, you can use the below query. Including the accountHolder field fetches the user's identity information

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 can be used to correlate transaction IDs within your system with the payments initiated by Stitch.

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:

ResponseStatusDescription
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 User Interaction Required

Similar to card, 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:

tip

Link the test data Capitec account to simulate this response when using a test client.

{
"errors": [
{
"message": "Multifactor Required to continue payment.",
"extensions": {
"code": "USER_INTERACTION_REQUIRED",
"userInteractionUrl": "https://secure.stitch.money/connect/payment-request/3991a32d-6d82-467e-ae47-5345022adc63",
"id": "cGF5aW5pdC8zOTkxYTMyZC02ZDgyLTQ2N2UtYWU0Ny01MzQ1MDIyYWRjNjM="
},
"locations": [
{
"line": 4,
"column": 23
}
],
"path": ["userInitiatePayment"]
}
],
"data": {
"__typename": "Mutation",
"userInitiatePayment": null
}
}

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": {
"code": "PAYMENT_FAILED",
"reason": "insufficient_funds"
}
}
],
"data": {
"__typename": "Mutation",
"userInitiatePayment": null
}
}
Possible Payment Errors

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

ValueDescription
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.

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 https://example.com/payment for payment requests, you'd append the following query string to the url returned from the API: ?redirect_uri=https%3A%2F%2Fexample.com%2Fpayment

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

http://example.com/payment

https://example.com/payment

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

Request FieldDescriptionType
idThe unique id of this payment requestID
statusStatus will have the value "complete" if successful, "closed" if the user clicked close in the UI, or "failed" if something went wrong when attempting the payment.String
externalReferenceThe value that was provided to the externalReference field when the payment initiation request was created.String

The id can be used to retrieve the final payment request status and other details from the Stitch API, as well as relate to incoming webhooks.

danger

The status field should not be used for any 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 the webhooks as the source of truth as they are secure and will always be sent from Stitch.
  2. making use of signed webhooks since you'll be able to verify the signature of each incoming webhook's request payload.

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":
redirect("/eft-success");
case "closed":
case "failed":
redirect("/eft-retry");
default:
break;
}

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.

Subscribing to LinkPay Webhooks

To receive a webhook upon payment completion or failure you will need to create a subscription for your client. Please see the example below to set up a basic unsigned webhook.

info

Please note that unlike the example shown on the Webhooks page that uses the paymentInitiationRequest node, to receive LinkPay webhooks, one should subscribe to the paymentInitiation node.

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.

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.

Retrieving Payment Initiation Status

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.

To retrieve the status of a payment initiation, you'll need a client token with the client_paymentauthorizationrequest scope.