InstantPay Integration Process
Generate Payment Request URL
InstantPay creation is protected by a client token. You'll need to follow the steps described in the client token guide
to obtain a client token with the client_paymentrequest
scope. To create a payment initiation request, you'll need to
ensure that the feature is enabled on your client.
To create the request, a GraphQL mutation is used to specify the requested amount, the references that will appear on the user and beneficiary's accounts, and the beneficiary details themselves.
An example of a GraphQL request to create a payment initiation request is shown below:
When creating a payment initiation request, 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
beneficiaryName
field is restricted to a maximum of 20 characters. - The
externalReference
field is restricted to a maximum of 4096 characters.
The two pieces of information you need from the response at this stage are the payment request id
, and the url
.
The payment request id
is used to correlate responses and to look up the status of the request in the API, and so
should be retained for later usage. The url
is used to enable the user to authorize the payment request, and you'll
need to redirect the user to this URL. We'll cover this in the next section.
If you're eagle-eyed, you may have noticed that you can specify either a single bankAccount
or a list of bankAccounts
when creating a payment request.
The bank account list was added because many companies open accounts at a number of different banks, and instruct users to pay into the same institution that they bank with. Companies often opt for this approach as intra-bank transfers typically clear near instantaneously.
Payment requests automate this account selection process by selecting the optimal account from the list for a given user.
The first bank account in the list acts as the preferred account and will be selected if a more optimal route is not found.
Surface URL and Handle Callback
The URL returned by the API requires that a whitelisted redirect_uri
is 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 test clients, we
do have the following URLs whitelisted by default:
- https://localhost:8080
- https://localhost:8080/return
- https://localhost:3000
- https://localhost:3000/return
- https://localhost:9000
- https://localhost:9000/return
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
.
The full URL you expose to the user should look like this
https://secure.stitch.money/connect/payment-request/2b068bd5-6a5a-42e1-8a45-673cb3ede612?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. For example
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 Field | Description | Type |
---|---|---|
id | The unique id of this payment request | ID |
status | Status 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 |
externalReference | The value that was provided to the externalReference field when the payment initiation request was created. It can be used to correlate transaction IDs within your system with the payment request initiated by Stitch | 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.
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:
- using the webhooks as the source of truth as they are secure and will always be sent from Stitch.
- 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 Initiation Requests
An optional expireAt
Date (ISO 8061) can be supplied in the creation of the payment initiation request which marks the
payment expired after the expireAt
date sets the payment request status to PaymentInitiationRequestExpired
.
Cancelling Pending Payment Initiation Requests
If the user clicks the X
on the dialog box, the payment initiation request will remain in the PaymentInitiationRequestPending
status. To cancel the payment request, you should call the clientPaymentInitiationRequestCancel
mutation, which also
triggers the cancel webhook event.
Payment Initiation Request Statuses
The table below describes the different statuses an InstantPay request can have, with the initial status always being PaymentInitiationRequestPending
:
Status | Description |
---|---|
PaymentInitiationRequestCompleted | This is a final payment state. |
PaymentInitiationRequestPending | The user hasn't yet completed the payment initiation request, or they exited the Stitch dialog box before completing the bank selection process. |
PaymentInitiationRequestCancelled | The payment initiation request was manually cancelled by the client. More information on this can be found here. |
PaymentInitiationRequestExpired | The payment initiation request has expired while awaiting user interaction. More information on this can be found here. |
Subscribe to Webhooks
To receive a webhook upon payment completion or expiry you will need to create a subscription for your client. Please see the example below to set up a basic unsigned webhook for InstantPay requests.
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.
Retrieving Payment Request Status
When receiving a callback from the payment request, you will likely want to check the status of the payment. Using the query below you can retrieve the status of a given payment by ID, in addition to information about the payer and beneficiary involved.
If a user closed the payment request interface, and expireAt
was supplied in the payment initiation creation request,
the payment will remain in the PaymentInitiationRequestPending
state until the expireAt
date has passed. The request
will only be in the PaymentInitiationRequestCancelled
state when the clientPaymentInitiationRequestCancel
mutation is called.
When a user has successfully initiated the payment, the state will be PaymentInitiationRequestCompleted
and contain details
of the payment, including the account selected and the specific beneficiary that the payment was made to.
To retrieve the status of a payment request, as described above, you'll need a client token with the client_paymentrequest
scope.
Payment Event Types
The events
field can provide insight in to the events that occurred during the payment process. To retrieve the events of a payment request, you'll need a client with the paymentevents
alpha flag.
Payment event __typename
and descriptions are outlined in the table below.
Status | Description |
---|---|
IncorrectLoginCredentials | The user entered incorrect login credentials when attempting to login. |
LoginMultifactorFailed | Login multifactor authentication was failed or was rejected. |
LoginMultifactorTimeout | Login multifactor authentication timed out while awaiting approval. |
PaymentMultifactorFailed | Payment multifactor authentication failed or was rejected. |
PaymentMultifactorTimeout | Payment multifactor authentication timed out while awaiting approval. |
BeneficiaryMultifactorFailed | Beneficiary multifactor authentication failed or was rejected. |
BeneficiaryMultifactorTimeout | Beneficiary multifactor authentication timed out while awaiting approval. |
InsufficientFundsForPayment | The bank rejected the payment due to the account having insufficient funds. |
DuplicatePayment | The bank does not allow duplicate payments. |
InvalidSourceAccount | The source account was not valid. |
InvalidDestinationAccount | The destination account was not valid. |
PaymentLimitsExceeded | The bank declined the payment because the payment exceeded the current limits. |
PaymentMinimumNotMet | The bank declined the payment due to payment minimum not met. |
BankTimeout | The bank timed out while processing a request. |
BankUnavailable | The bank was partially or fully unavailable while processing a request. |
BankError | An error occurred at the bank while processing a request. |
AccountBlockedByBank | Request was rejected by the bank due to the account being blocked. |
PaymentDeclinedByBank | The bank declined the payment. |
Testing InstantPay Events
Not all events are easily reproducible. Some of the events which can be simulated for test clients are as follows:
Status | How to Test |
---|---|
InvalidDestinationAccount | Use a beneficiary account that starts with 999 |
PaymentLimitsExceeded | Use a payment amount above one million ZAR |
PaymentMinimumNotMet | Use a payment amount less than ZAR 1.00 |
DuplicatePayment | Set beneficiaryRef as KombuchaFizz and amount ZAR 10.00 |
InsufficientFundsForPayment | Use a payment amount greater than the respective account balance |
PaymentMultifactorFailed | Use an account number that starts with 888 |
PaymentMultifactorTimeout | Use an account number that ends with 888 |
Testing InstantPay Initiation
To test this process on your browser and run all the GraphQL examples in this guide prior to integrating with Stitch, you can use our sandbox. Learn more about the sandbox here.
Postman Collection
You can also test InstantPay with the Postman collection available for download here. Please import and review the collection's code, supplying the variables where required, then you can try out the requests in this guide.