Skip to main content

Buy Now, Pay Later Integration Process

BNPL payments can be made easily by creating payment requests via the Stitch API. Users can then be redirected to the Stitch Consumer App, for them to select an instalment plan, input card details for subsequent collections, and authorise the initial instalment.

Generate Payment Request URL

Similarly to creating Pay By Bank or Card payments, BNPL payment request 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 the request, a GraphQL mutation is used to specify the requested amount, references, and order information.

The GraphQL API URL https://api.stitch.money/graphql can be used for all payment requests (whether on test or live clients).

An example of a GraphQL request to create a payment initiation request with the BNPL payment method is shown below:

BNPL Payment Method Details

Please note that:

  • The paymentMethods.bnpl type requires client configuration. Contact support@stitch.money to assist in enabling your client for this feature.
  • Not setting the paymentMethods field results in the Pay by Bank method being enabled on your payment request. To explicitly omit Pay by Bank as payment method, specify the paymentMethods.eft.enabled field with a value of false.

Expiring Payment Requests

It is recommended that an expireAt Date (ISO 8601) is supplied in the creation of any payment initiation request. At the specified date and time, the payment request status will automatically transition to PaymentInitiationRequestExpired, if the payment is not yet complete.

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:

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
Whitelisting Redirect URLs

To add or remove a URL from the whitelist, please reach out to the Stitch team.

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

http://example.com/payment

https://example.com/payment

The user completes the BNPL payment on the Stitch Consumer App. The user can use the application to manage their profile and view the status of their orders. Once the user authorises the initial charge and completes the payment, 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 Stitch ID of the payment requestID

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

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. Webhooks are secure and will always be sent from Stitch.
  2. Using signed webhooks that support signature verification of incoming webhook payloads.

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

Cancelling Pending Payment Requests

To cancel a BNPL payment request, you should call the clientPaymentInitiationRequestCancel mutation. This API request triggers a corresponding webhook dispatch.

Payment Initiation Request Statuses

The table below describes the different statuses a BNPL request can have, with the initial status always being PaymentInitiationRequestPending:

StatusDescription
PaymentInitiationRequestCompletedThe user has completed the payment initiation request and is a final state.
PaymentInitiationRequestPendingThe user has not completed the payment initiation request
PaymentInitiationRequestCancelledThe payment initiation request was cancelled by the client. More information on this can be found here.
PaymentInitiationRequestExpiredThe payment initiation request has expired whilst awaiting user interaction. More information on this can be found here.

Subscribe to Webhooks

Since BNPL requests function similarly to Pay By Bank, we subscribe to payment webhooks and receive payment updates in the same way.

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.

Webhook Statuses

The payment webhook will be dispatched for each of the following status updates:

  • PaymentInitiationRequestCompleted
  • PaymentInitiationRequestCancelled
  • PaymentInitiationRequestExpired
Example Payload
{
"data": {
"client": {
"paymentInitiationRequests": {
"node": {
"__typename": "PaymentInitiationRequest",
"amount": {
"currency": "ZAR",
"quantity": "1"
},
"bankBeneficiaries": [
{
"__typename": "BankBeneficiary",
"accountNumber": "1234567890",
"bankAccountNumber": "1234567890",
"bankId": "nedbank",
"name": "FizzBuzz Co."
}
],
"beneficiaries": [
{
"__typename": "BankBeneficiary",
"accountNumber": "1234567890",
"bankAccountNumber": "1234567890",
"bankId": "nedbank",
"name": "FizzBuzz Co."
}
],
"beneficiaryReference": "KombuchaFizz",
"cancellationReason": null,
"created": "2022-10-11T09:52:13.312Z",
"createdAt": "2022-10-11T09:52:13.312Z",
"currency": "ZAR",
"events": [],
"externalReference": "79261d16-c53b-48eb-9019-dc9cfb6c5126",
"failureReason": null,
"id": "cGF5cmVxLzk2YjUyODU1LTBkMzQtNDI0MS04YmM2LWE4ODBlMDQ1ZGQzOQ==",
"payerConstraints": null,
"payerReference": "Joe-Fizz-01",
"paymentConfirmation": {
"__typename": "PaymentPending",
"date": "2022-10-11T09:52:53.128Z"
},
"paymentMethods": [
{
"cash": {
"atm": {
"enabled": true
},
"retailer": {
"barcodeNumber": "test-11132098754321",
"barcodeUrl": "https://test-barcode-url.com",
"enabled": true
}
}
},
{
"eft": {
"enabled": true
}
}
],
"paymentRequestPayerConstraintRelationship": null,
"quantity": "1",
"refunds": [],
"state": {
"__typename": "PaymentInitiationRequestCompleted",
"amount": {
"currency": "ZAR",
"quantity": 1
},
"beneficiary": {
"__typename": "BankBeneficiary",
"accountNumber": "1234567890",
"bankAccountNumber": "1234567890",
"bankId": "nedbank",
"name": "FizzBuzz Co."
},
"date": "2022-10-11T09:52:53.114Z",
"id": "96b52855-0d34-4241-8bc6-a880e045dd39",
"payer": {
"__typename": "PaymentInitiationBankAccountPayer",
"accountName": "Current account",
"accountNumber": "4104754941",
"accountType": "current",
"bankId": "absa"
},
"proofOfPayment": null
},
"updated": "2022-10-11T09:52:53.128Z",
"updatedAt": "2022-10-11T09:52:53.128Z",
"url": "https://secure-local.stitchmoney.com/connect/payment-request/96b52855-0d34-4241-8bc6-a880e045dd39",
"userReference": "Joe-Fizz-01"
}
}
}
}
}

Retrieving Payment Request Status

The status of a BNPL request works much like Pay By Bank.

Use the following GraphQL query to retrieve the payment request status.

Postman Collection

BNPL requests can be created and tested using the Postman collection available here. These can be used by specifying your client credentials and supplying the custom request variables where required.