Payments - Online

This guide describes how the online payment flow works in detail.

1 - Add Waave to check out

Add Waave Pay by Bank as a payment method to your checkout. Multiple UI options are available to suit your checkout experience and technology stack. Discuss with your Waave Team representative for more detail.

2 - Get access token

Implement server side logic to pass your client id and secret to the Waave token API to obtain an access token. The access token returned by this logic will be required to make subsequent calls to Waave APIs.

The merchant should cache the access token until its expiry.

🚧

The merchant client id and secret must not be exposed to the browser. Only short-lived access tokens can be sent to the browser.

In addition, never use refunds scope when requesting an access token for the browser.

Token API end point URIs:

Sample Request

{
    "client_id":MERCHANT_CLIENT_ID,
    "client_secret":MERCHANT_CLIENT_SECRET,
    "scope":"payment-sessions:create payment-sessions.status:read"
}

Sample Response

{
    "access_token": "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxYjg3MGNkNy1lODdjLTRkZTYtYTExNS05Y2I1NzBkZDk5NTIiLCJhdXRoIjoiUk9MRV9XU19VU0VSIiwic2NvcGUiOiJwYXltZW50LXNlc3Npb25zOmNyZWF0ZSBwYXltZW50LXNlc3Npb25zLnN0YXR1czpyZWFkIiwiZXhwIjoxNjU0ODI1OTgwfQ.nOZNzpHicZkFtmsK4LJNRD44QuGlja8UBoyv_1JiUlTdGYTadq0Qe_yK8LV9e_RMgKeusb6xTk0ZbMzj6bgbZn7h9ZC6g942gjhFyIIQwY0tpLaFcU5cC5wfdcIIwdKDHcQNnXz1J6mNHnJlmgbmRijYdR21q-CxFZJ3j3TScYUDAyoz9_8usI8UeLjWrzveU1DZvGd1jKJFmnqDJntuBtDjW107rADZaaGrAmidC-QXrLJx90z7YxVu8N5B0lQTd67mQILWpONAVLLeFTCDEtQEMXLb1O_ENlYw6ZdyF8RzukfW0Nz91OMml86VlrRKG1IaiSKg1WhyI9YvhiTiuQ",
    "expires": 86400
}

3 - Create a Payment

If the customer selects Waave as payment method, call Create Payment API (Online) to create a Payment using the access token obtained in the previous step.

Sample Request

{
    "customerReference": "orderRef-20220610123125",  
    "totalAmount": 900,
    "currency": "AUD",
    "effectiveFromAt": null,
    "effectiveToAt": "2022-07-11T04:40:42.500126870Z",
    "returnUrl": "https://your_return_url",
    "notificationUrl": "https://your_notification_url", 
    "businessCode": "your_business_code",
    "billingAddress": {
        "line1": "Halloween Street",
        "line2": "House No.23",
        "city": "Melbourne",
        "state": "Victoria",
        "postcode": "3006",
        "country": "Australia"
    },
    "shippingAddress": {
        "line1": "Halloween Street",
        "line2": "House No.23",
        "city": "Melbourne",
        "state": "Victoria",
        "postcode": "3006",
        "country": "Australia"
    },
    "orderItems": [
        {
            "name": "bournvita health drink",
            "quantity": 1,
            "amount": 900,
            "currency": "AUD"
        }
    ],
  	"email": "[email protected]",
  	"phoneNumber": "0412345678",
    "additionalData": {
        "firstName": "Jane",
        "lastName": "Doe"
    },
  	"dataHolderBrandId": null
}
FieldDescription / Notes
customerReferenceOptionalMerchant specified reference for the order / payment.
totalAmountMandatoryTotal payment amount in cents (e.g. $120.50 should be passed as 12050)
currencyOptionalIf not specified, defaults to AUD.
effectiveFromAtOptionalIf specified, Waave will reject payment authorisation attempts by the shopper prior to the time specified.
effectiveToAtOptional
(Recommended)
If specified, Waave will reject payment authorisation attempts by the shopper after the time specified. You must set this field to a time before cart expiry on the merchant's checkout. This prevents payment authorisation after the cart expires, which would necessitate a refund.
returnUrlRequiredMerchant's call back URL to which Waave will send the shopper after they have authorised or cancelled payment, or there is an error.
notificationUrlOptionalWebhook URL to which Waave will post the status updates for this payment. Leave blank if web hooks are not required.
businessCodeMandatoryProvided by the Waave team during onboarding.
billingAddressOptionalCustomer billing address.
shippingAddressOptionalCustomer shipping address.
orderItemsMandatoryArray of line items in the cart.
emailMandatoryCustomer email address.
phoneNumberOptional (Recommended)Customer phone number. If the merchant captures both home and mobile phone numbers, map the mobile phone number. If populated, Waave will use this information to pre-populate the sign up forms to streamline the user experience.
additionalDataOptional (Recommended)All fields under additionalData are optional. If populated, Waave will use this information to pre-populate the sign up forms to streamline the user experience and to assess payment risks.
dataHolderBrandIdOptionalIf your checkout has integrated bank selection, provide the brandId of the selected bank.

This API supports idempotency. See this section for more detail.

Sample Response

{
    "paymentSessionId": "1fd302b1-5876-4629-bd1a-77eba6a1e647",
    "customerReference": "orderRef-20220610123125",
    "totalAmount": 900,
    "currency": "AUD",
    "businessCode": "your_business_code",
    "createdAt": "2023-04-26T12:23:48.329412315Z",
    "expiresAt": "2023-04-26T13:23:48.306020434Z",
    "status": "AWAITING_AUTHORISATION",
    "payUrl": "https://link.app.waavetest.com/pay/w/1fd302b1-5876-4629-bd1a-77eba6a1e647?r=true",
    "billingAddress": {
        "id": 204152,
        "line1": "Halloween Street",
        "line2": "House No.23",
        "city": "Melbourne",
        "state": "Victoria",
        "postcode": "3006",
        "country": "Australia"
    },
    "shippingAddress": {
        "id": 204202,
        "line1": "Halloween Street",
        "line2": "House No.23",
        "city": "Melbourne",
        "state": "Victoria",
        "postcode": "3006",
        "country": "Australia"
    },
    "orderItems": [
        {
            "id": 204302,
            "name": "bournvita health drink",
            "sku": null,
            "quantity": 1,
            "amount": 900,
            "currency": "AUD"
        }
    ],
    "returnUrl": "https://your_return_url",
    "notificationUrl": "https://your_notification_url",
    "effectiveFromAt": null,
    "effectiveToAt": "2022-07-11T04:40:42.500126870Z",
    "email": "[email protected]",
    "phoneNumber": "0412345678",
    "additionalData": {
        "firstName": "Jane",
        "lastName": "Doe"
    },
    "dataHolderBrandId": null
}

The response contains a unique payUrl which is required in the next step.


4 - Send the shopper to Waave Pay by Bank

Once the Payment object has been created, you need to redirect the shopper to the Pay URL.

The shopper will interact with the Waave Pay by Bank UI to complete sign up and payment authorisation.

Once the payment is authorised or cancelled, the Waave Pay by Bank will redirect the shopper to the returnUrl specified during the payment session creation, along with additional parameters.

  • resultCode - indicates the outcome of the payment. It can be APPROVED, DECLINED, ERROR or CANCELLED.
  • paymentSessionId - the payment session ID.
  • businessCode - the merchant's business code.

While testing your integration in the sandbox environment, you can simulate the shopper authorising (or cancelling) the payment by using the Payment Simulator API. This API enables integration testing without the need to manually go through the Waave Pay by Bank UI as the shopper. For more details, see the Simulating Payment Authorisation section below.


5 - Verify Payment Status

Once the shopper has landed on the merchant's returnUrl, the merchant must verify the payment status by calling the Get Payment Status API with the paymentSessionId.

Based on the status being returned, you must take different actions:

  • INSTRUCTION_SENT - the shopper has authorised the payment in the Waave app and the payment has been submitted. This is the only status that indicates successful payment authorisation.
  • EXPIRED - The payment session has expired.
  • DECLINED - Waave have declined the payment.
  • CANCELLED - The payment session has been cancelled by the merchant or the shopper.
  • ERROR - There was an error while processing the payment session.

There are other statuses that this API can return, such as AWAITING_AUTHORISATION. If it does, you need to keep polling the API until one of the final statuses mentioned above is returned. See Statuses for a complete list of statuses.

Sample Response

{
    "status": "INSTRUCTION_SENT", 
    "resultCode": null,
    "resultUrl": null
}

It is strongly recommended that your server-side logic calls the Get Payment Status API before fulfilling the order. Solely relying on status verification done in JavaScript running in the browser would make your application susceptible to malicious manipulation of data. Additionally, calling the API from the server-side will safely confirm the final state of the payment session regardless of whether the shopper closes the browser.

The merchant can also subscribe to payment notification webhooks. Refer to Webhooks - Payment Notifications for more details.


6 - Cancel a Payment

The merchant can explicitly cancel a payment by calling the Cancel Payment API. If the shopper attempts to authorise a cancelled payment, they recieve an error.

This is recommended when the payment session should be voided (and potentially a new one created separately). Examples include:

  • Shopping cart expiry has been detected
  • Shopper has updated the cart content / total amount
  • Shopper has cancelled the checkout process
  • Shopper has clicked the browser back button or refresh button

Once a payment session is authorised it cannot be cancelled. You will need to initiate a refund instead. See Refunds for more details.

First, implement logic to pass your client id and secret to the Waave token API to obtain an access token with the scope 'payment-sessions:cancel'.

Sample Request

{
    "client_id":MERCHANT_CLIENT_ID,
    "client_secret":MERCHANT_CLIENT_SECRET,
    "scope":"payment-sessions:cancel"
}

Sample Response

{
    "access_token": "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiIxYjg3MGNkNy1lODdjLTRkZTYtYTExNS05Y2I1NzBkZDk5NTIiLCJhdXRoIjoiUk9MRV9XU19VU0VSIiwic2NvcGUiOiJwYXltZW50LXNlc3Npb25zOmNyZWF0ZSBwYXltZW50LXNlc3Npb25zLnN0YXR1czpyZWFkIiwiZXhwIjoxNjU0ODI1OTgwfQ.nOZNzpHicZkFtmsK4LJNRD44QuGlja8UBoyv_1JiUlTdGYTadq0Qe_yK8LV9e_RMgKeusb6xTk0ZbMzj6bgbZn7h9ZC6g942gjhFyIIQwY0tpLaFcU5cC5wfdcIIwdKDHcQNnXz1J6mNHnJlmgbmRijYdR21q-CxFZJ3j3TScYUDAyoz9_8usI8UeLjWrzveU1DZvGd1jKJFmnqDJntuBtDjW107rADZaaGrAmidC-QXrLJx90z7YxVu8N5B0lQTd67mQILWpONAVLLeFTCDEtQEMXLb1O_ENlYw6ZdyF8RzukfW0Nz91OMml86VlrRKG1IaiSKg1WhyI9YvhiTiuQ",
    "expires": 86400
}

Then call the the Cancel Payment API with the token provided. The API will return a 200 response indicating that the payment session has been invalidated. If the shopper attempts to authorise this payment session, they will receive an error.

If you receive the following error, the payment session has already been authorised by the customer and it cannot be cancelled. If this occurs, the merchant can initiate a refund, or alternatively fulfil the order if that is deemed to be the appropriate action.

{
    "entityName": "paymentSession",
    "errorKey": "cancel-not-allowed",
    "type": "https://www.waave.com/problem/problem-with-message",
    "title": "Cannot perform cancel on payment session already having status INSTRUCTION_SENT",
    "status": 400,
    "message": "error.cancel-not-allowed",
    "params": "paymentSession"
}

Testing your integration

We provide two methods for testing your integration.

Manual Testing

You can go through the Pay By Bank payment flow in a browser as a real customer would.

The Pay by Bank flow normally requires the customer to log in using a mobile phone number, enter the OTP (one-time pin) sent to the number, and link a valid bank account with sufficient funds.

In the sandbox environment, you can simulate different payment scenarios by using pre-defined shopper details to authorise the payment. When redirected to Pay by Bank, use the details below to bypass the OTP challenge and simulate your desired scenario:

EmailPhone NumberScenario
[email protected]0400000001Customer (payer) choice: ACCEPTED or CANCELLED
[email protected]0400000002Network decision: DECLINED
[email protected]0400000003Bank technical fault: ERROR

In all scenarios, you will be redirected to the payment authorisation screen, where you can simply click 'Pay' to complete payment or 'Cancel' to test payment cancellation by the shopper. For the customer (payer) choice scenario, the decision to 'Pay' or 'Cancel' will be honoured. For the other scenarios, the payment outcome is fixed.

Simulating Payment Authorisation

If you prefer to use a command line tool or Postman rather than a browser, we provide a Payment Simulator API that enables the merchant to test payment authorisation and cancellation by the shopper.

To use this API, first obtain an access token using your merchant credentials and special scope simulator.payment-sessions:comlete.

Sample Request

{
    "client_id":MERCHANT_CLIENT_ID,
    "client_secret":MERCHANT_CLIENT_SECRET,
    "scope":"simulator.payment-sessions:complete"
}

Once an access token is obtained, make a POST call to the simulator API as below.

Simulator API endpoint URI:

Sample Request

{
    "action":"ACCEPTED"
}

You can simulate the following shopper actions by passing the corresponding values in the action field.

  • ACCEPTED- Shopper authorises the payment in the Waave Pay by Bank UI.
  • CANCELLED- Shopper cancels the payment in the Waave Pay by Bank UI.
  • DECLINED - Waave or the banking network declines the payment.
  • ERROR - Technical fault from the banking network.

The API simulates the shopper performing the action requested and responds back with a resultUrl. This is the URL, to which the Waave Pay By Bank UI would have redirected the shopper. You can use this URL to simulate the shopper being redirected back to your site after payment authorisation to complete the flow.

Sample Response

{
    "resultUrl": "https://www.your-site.com/result.html?paymentSessionId=c71892ae-1237-495b-b94c-6f1e290f84a3&resultCode=APPROVED&businessCode=bens_bakeshop"
}

Notes on idempotency

Waave APIs that create resources such as Create Payment API (Online) , Payments - In Store Flowand Create Refund API support idempotency to allow merchants to safely retry requests when a network issue occurs.

To perform an idempotent request, simply add an additional Idempotency-Key header to the request. Waave will save the response message of the first request made for given idempotency keys for 24 hours, and subsequent requests with the same key will return the same result as the first request. We recommend you use UUIDs or similar to ensure uniqueness.

$ curl https://test01.app.waavetest.com/platform/api/channel/v1/business/payments \
  -H "Idempotency-Key: 7ddd80f1-82dc-4dfb-8b3f-7415f9691ac9" \

What’s Next