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
- Get a client token.
- Generate the payment authorization request url.
- Surface the url to the user using the user authorization flow.
- Get a user token.
- Initiate a payment using a user token.
- When required, handle the user interaction during payment initiation.
- 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
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
- The LinkPay product is not supported in iFrames.
- 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.
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 / Error | Status | Description |
---|---|---|
PaymentInitiationCompleted | PaymentInitiationCompleted | This is a final payment state, indicating successful movement of funds. |
USER_INTERACTION_REQUIRED | PaymentInitiationPending | The bank requires the user to complete a manual action. More explanation on how to handle this here. |
PAYMENT_FAILED | PaymentInitiationFailed | This is a final payment state, indicating that the payment failed for one of the reasons explained here. |
PaymentInitiationExpired | PaymentInitiationExpired | The payment has expired while awaiting user interaction. More information on payment initiation expiry can be found here. |
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": {
"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": {
"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 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
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 Field | Description | Type |
---|---|---|
id | The unique ID of this payment request. | ID |
externalReference | The value that was provided to the externalReference field when the payment initiation request was created. | String |
status | The 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.
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:
- Using webhooks as the source of truth for payment status updates, which can also be expected at the time these updates occur.
- 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":
redirect("/eft-success");
case "closed":
case "failed":
redirect("/eft-retry");
default:
break;
}
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:
Value | Description |
---|---|
bank_error | Payment failed because a bank error has occurred. |
blocked | Payment failed due to blocked account. |
declined | Payment has been declined. |
duplicate_payment | Payment failed because a duplicate payment has already occurred. |
invalid_destination_account | Payment failed due to an invalid destination account. |
invalid_source_account | Payment failed due to an invalid source account. |
limits_exceeded | Payment failed due to account limits exceeded. |
limits_not_met | Payment failed due to payment minimum not met. |
readonly_account_error | Payment failed as this account is read only. |
timeout | Payment failed due to a timeout. |
payment_pending | Error marking payment as complete. Please contact the Stitch team if you encounter this error. |
unknown | Payment failed due to an unknown error. |
insufficient_funds | Payment 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.