PaymentRequest APIs

Overview

This page will walk you through the steps you need to follow when integrating to our suite of PaymentRequest APIs. Use this to receive payments with PayID, either using our Payment Request App or your own custom build on top of our APIs.

The Azupay Rest API has an entity called PaymentRequest. It is used to create a PayID that your customers can send payments to. The PaymentRequest entity is central to the management of the PayID payment experience. If you choose to use our PaymentRequest App our API will return a URL to invoke our PaymentRequest Checkout App to ensure optimum user experience for your customers and reduce your development time.

In the example API calls below, we will assume you already have an API Key (e.g.SECR_MYBUSINESSID_nR2duCGXlqWSuYJF) with Azupay.

Types of PayIDs

Different types of PayIDs can be configured - such as Dynamic PayID or Open Static PayID. The former is for accepting a single payment at a point in time and the latter is for accepting multiple payments over time to the same PayID. Let's discuss these in the most basic form first and then take a look at how you can tweak their behaviour with special features later on in this guide.

Dynamic PayID

This type of PayID can only receive a single payment and is useful in situations where your customers make a one-off purchase of goods, or pay a single invoice. The main characteristics of this type of PayIDs are:

  • Can only receive a single payment.
  • Once completed, the PayID will be de-registered.

To create it issue the following API call:

POST https://api.azupay.com.au/v1/paymentRequest
Authorization: SECR_MYBUSINESSID_nR2duCGXlqWSuYJF
Content-Type: application/json
{
  "PaymentRequest": {
    "clientId": "MYBUSINESSID",
    "clientTransactionId": "INV-0000001-1",
    "paymentAmount": 32.12,
    "paymentDescription": "Client invoice numner INV-0000001"
  }
}

This is a very simple request message. Now let's have a look at what you submitted:

  • clientId: your unique client identifier that we provide you during onboarding.
  • clientTransactionId: a unique identifier for your business that does not repeat. If you send the same clientTransactionId in another request the system will not create a new one, but will return the status of the existing one. This serves as a duplicate check in case your HTTP client retries the same message. So it is a good practice to use a globally unique identifier (GUID) or append an extra counter to your invoice identifier in case you need to recreate the PaymentRequest.
  • paymentAmount: the amount you expect to receive. By default your Azupay account will be configured to receive an exact amount. If a different amount is received, Azupay will return that payment immediately. You can ask for this configuration to be changed to receive under, overpayments or any amount.
  • paymentDescription: additional description that will show for your payer and appear in your Client Dashboard and reports.

Once you submit this request you will receive a response like the following.

HTTP/1.1 200 OK
Date: Wed, 21 Apr 2021 03:36:47 GMT
Content-Type: application/json
{
  "PaymentRequest": {
    "clientId": "MYBUSINESSID",
    "clientTransactionId": "INV-0000001-1",
    "paymentAmount": 32.12,
    "paymentDescription": "Client invoice numner INV-0000001",
    "payID": "[email protected]"
  },
  "PaymentRequestStatus": {
    "paymentRequestId": "a050551479f625c066b559da28fee33c",
    "status": "WAITING",
    "createdDateTime": "2021-04-21T03:36:45.115Z"
  }
}

You can see there are some additional fields on the PaymentRequest as well as a new entity called PaymentRequestStatus.

For the PaymentRequest:

  • payID: the unique PayID generated for this transaction. Note it uses a domain mybusiness.com. This domain is configured for your business during onboarding. As part of onboarding we validate you have ownership of the domain.

The returned PaymentRequestStatus gives information about the newly created PaymentRequest. These are the fields:

  • paymentRequestId: an identifier generated by Azupay. Used to reference the object in subsequent operations such as getPaymentRequest and refundPaymentRequest. It is a good idea to store this identifier in your database so that you can enquire about the status later. You can also use it as a search parameter in the Client Dashboard
  • status: the status. Given you have just created it, its status is WAITING as in waiting for your customer to complete the payment. See the PayID Statuses at bottom of this page for more information about the status.

At this point the customer would have to go to their banking app and complete the payment to the PayID.

👍

Test Bank available!

If you are testing in our sandbox environment, you can complete payments to a PayID using our Test Bank utility. This tools simulates what your customer will do on their banking app to complete the payment.

You just have to enter the PayID you want to pay to and complete the payment.

Open Static PayID

This is a different type of PayID that supports your customers to make multiple payments over time. It can be useful in situations like a customer wallet where you create a PayID for each customer and they use the same PayID repeatedly over time to top-up their account with you.

A few different rules apply for Open Static PayIDs:

  • The request must have the multiPayment field set to true
  • The status of these will always be WAITING.
  • The PayID description that your customers see will contain what was provided in the paymentDescription field.
  • Notification webhooks will contain a parentPaymentRequestId that corresponds to the paymentRequestId for this Multiple Payment PayID PaymentRequest.

📘

Open Static PayIDs require a webhook to keep you updated on statuses

With Open Static PayIDs, the only way to learn about new incoming payments made to them is via a webhook endpoint or manually checking your Client Dashboard, so we recommend you provide the paymentNotification in the request. See the webhooks for Multiple Payment PayID's section for more details.

An Open Static PayID does not have an amount set, but you can set an amount to support a slightly different user experience with the Recycled Static PayID. See Open Static PayID Amount Limits heading below to see the impact of setting an amount.

Features

The following are features that you can apply over and above the Dynamic or Open Static PayID.

Customising the PayID

By default, Azupay will generate the PayID for you. You can also optionally supply a PayID you would like to register. If available, it will be used. Simply supply the value in the request body as follows:

POST https://api.azupay.com.au/v1/paymentRequest
Authorization: SECR_MYBUSINESSID_myapikey
Content-Type: application/json
{
  "PaymentRequest": {
    "clientId": "MYBUSINESSID",
    "clientTransactionId": "INV-0000001-1",
    "paymentAmount": 32.12,
    "paymentDescription": "Client invoice numner INV-0000001",
    "payID": "[email protected]"
  }
}

Note that the domain portion of the PayID, in this case '@somewhere.com' must be a domain that you own. We will verify ownership of this domain during onboarding.

Time limiting

You can apply time based limits on your PaymentRequests by specifying a point in time in the future via paymentExpiryDatetime field. This field will be set automatically by Azupay if no value is supplied for Dynamic PayID PaymentRequest based on your default value.

Amount limiting

You can apply limits to the amount paid to a PayID as follows:

Dynamic PayID amount limits

  • Set the amount you expect to receive

Note: the Azupay system defaults to expecting a single perfect payment, in the Dynamic PayID topic above, the API call did not specify the multiPayment field so our platform will default to only allow your payers to send a single payment that exactly matches the specified payment amount.

Open Static PayID amount limits

We use the term Static PayID to refer to PayIDs we create for you that remain over time to be used repeatedly. Different behaviours for these series of payment experiences can be created by setting an amount.

To recap from Open Static PayID topic above, multiPayment = TRUE will create an Open Static PayID

  1. No amount. For this payment request, we will accept any number of payments, of any amount, any time and the PayID will remain open.
    This is the Open Static PayID.
  2. Set amount. For this payment request, we will accept any number of payments, of any amount up to the specified amount. If the payment is overpaid on the last transaction, we will return the difference. Once the target amount is received we will deregister the PayID, which will prevent duplicate payments or further attempts to incorrectly overpay the amount.
    The PayID can be used repeatedly by creating new Payment Requests using the same PayID string but specifying whatever you need for the new payment (e.g. different set amount and different description).
    When this is done the payer can pay to the same PayID they saved in their own bank payee list and subsequent payments will see description and target amount you set for the new Payment Request.
    This is the Recycled Static PayID.

Updating a PayID

You can change the conditions that apply to a PayID created previously by submitting a new PaymentRequest with the same payID but different clientTransactionId. This will cause the API to expire any existing PaymentRequest and create the new one.

For example, if you usually create a single PayID per client, something like [email protected]. You would create a first PaymentRequest like the one below:

POST https://api.azupay.com.au/v1/paymentRequest
Authorization: SECR_MYBUSINESSID_myapikey
Content-Type: application/json
{
  "PaymentRequest": {
    "clientId": "MYBUSINESSID",
    "clientTransactionId": "INV-0000001",
    "paymentAmount": 40.00,
    "paymentDescription": "Monthly invoice INV-0000001 for client 234",
    "payID": "[email protected]",
    "paymentExpiryDatetime": "<last day of September>"
  }
}

Now if its end of the month, your client hasn't paid for invoice INV-0000001 and you have generated a new invoice INV-0000002 with the remaining balance you can submit a new PaymentRequest that would reflect the latest state of their account. Something like this:

POST https://api.azupay.com.au/v1/paymentRequest
Authorization: SECR_MYBUSINESSID_myapikey
Content-Type: application/json
{
  "PaymentRequest": {
    "clientId": "MYBUSINESSID",
    "clientTransactionId": "INV-0000002",
    "paymentAmount": 80.00,
    "paymentDescription": "Monthly invoice INV-0000001 for client 234",
    "payID": "[email protected]",
    "paymentExpiryDatetime": "<last day of October>"
  }
}

Note that the clientTransactionId has a different value. Now your client would have to pay $80 instead of $40 and would see an updated description for the PayID when they look it up on their online banking app. The new PaymentRequest will also have a new paymentRequestId, this will be returned to you in the response of the second call.

This is the functionality that supports our Recycled Static PayID.

Incorrect payments

Sometimes your customer might submit a payment with an incorrect amount. Depending on whether it's to a Dynamic, Open Static or Recycled Static PayID, the behaviour will vary.

Where it's to a Dynamic Payment PayID, Azupay will return the funds back immediately since our system is expecting a single exact match amount only. If you are using our Payment Request App our UX will handle error messaging to the payer elegantly and encourage them to pay the correct amount.

Where it's to a Recycled Static PayID (it has been limited by amount), any underpaid amount will be retained. If an overpaid amount is sent the target amount will retained and any surplus will be refunded. If you are using our Payment Request App our UX will display a success message and also inform the payer that they were refunded the surplus amount.

Handling incorrect payments when not using our UX Apps

In the case of an overpayment to a Dynamic PayID, if you are not using our UX, it is critical you notify the customer of such errors so that they can submit the payment again. In the case of an overpayment to a Recycled Static PayID you should notify the customer the surplus has been refunded otherwise they may expect a credit note from you.

In cases when the target amount has not been reached the PayID will remain in WAITING and the PaymentRequestStatus object will be enriched with information about the payment attempts. When you enquire about the PaymentRequest you will get a result like the following:

"PaymentRequest": {...}
"PaymentRequestStatus": {
  ...
  "failedPaymentAttempts": [
    {
      "attemptDateTime": "2021-06-02T23:35:12.940Z",
      "attemptAmount": 30,
      "attemptFailureReason": "Incorrect Payment Amount"
    }
  ],
  "status": "WAITING"
}

With this information you can advise your customer to retry the payment with the correct amount.

Payment status

Given that the payment is initiated from the payer bank app, you need to verify the status of the payment either using a GET /v1/paymentRequest call. You could also use a webhook notification to receive updates on the status that will be explained further in this document.

To enquire about the status of a PaymentRequest you can perform GET call using the paymentRequestId that was returned in the PaymentRequestStatus. The request will look like this:

GET https://api.azupay.com.au/v1/paymentRequest?id=a050551479f625c066b559da28fee33c
Authorization: SECR_MYBUSINESSID_myapikey
Content-Type: application/json

The status will be in WAITING until completed by the payer, when the status will become COMPLETE. Note that an Open Static PayID never reaches COMPLETE status, rather the individual payments received against it reach this status.

{
  "PaymentRequest": {
    "clientId": "MYBUSINESSID",
    "clientTransactionId": "INV-0000001-1",
    "paymentAmount": 32.12,
    "paymentDescription": "Client invoice numner INV-0000001",
    "payID": "[email protected]",
    "paymentExpiryDatetime": "2021-04-21T03:51:45.256Z"
  },
  "PaymentRequestStatus": {
    "paymentRequestId": "a050551479f625c066b559da28fee33c",
    "createdDateTime": "2021-04-21T03:36:45.115Z",
    "payerPaymentDescription": "paying for my goods and services",
    "status": "COMPLETE",
    "amountReceived": 32.12,
    "completedDatetime": "2021-04-22T05:07:54.025Z"
  }
}

There are additional fields returned besides the new status:

  • amountReceived: usually should be the same as the paymentAmount
  • completedDatetime: the timestamp when the payment was received by Azupay.

Advanced PayID customisation

Custom description

By default, when you create a PayID, the description that the payer sees on their banking application looks something like the following:

The entire description is a concatenation of your organisation name (My business full legal name), the amount ($32.12) and payment description (INV-0000001).

Given the Open Static PayIDs do not have an amount, the description will just omit amount, but
the rest will be the same. It will look something like the following:

You can customise the payment description when creating the PaymentRequest like the following:

{
  "PaymentRequest": {
    ...
    "paymentAmount": 32.12,
    "paymentDescription": "Invoice INV-0000001",
    ...
  },
  ...
}

Note that the organisation name at the beginning corresponds to the full legal name that was provided during on-boarding. Sometimes your customers may not recognise your company's full legal name and it will be more appropriate to use your trading name.
The next section shows how you can customise the organisation name for a particular PayID domain.

🚧

It is a requirement that the organisation name reflects the name your business is known by in the market

We default to using your legal name and will need to review any other organisation names you want to use to ensure they are reflect your business correctly.

Custom brand or organisation name

You can assign a custom Organisation or Merchant name specific domains that would reflect in the payment description either as you onboard or by using our payIdDomains API endpoint. The endpoint to update domains is not enabled by default, and you would need to specifically request it to be included when signing the commercial agreement with Azupay.

You can start by enquiring about the domains that are configured in your account.

GET https://api.azupay.com.au/v1/config/payIdDomains
Authorization: SECR_MYBUSINESSID_myapikey
Content-Type: application/json

Then you will get a list like the following:

[
  {
    "domain": "mybusiness.com"
  }
]

Now, if you want the organisation name to be My Business Brand for all payIDs with domain mybusiness.com then you can send the following request.

POST https://api.azupay.com.au/v1/config/payIdDomains
Authorization: SECR_MYBUSINESSID_myapikey
Content-Type: application/json

[
  {
    "domain": "mybusiness.com",
    "merchantName": "My Business Brand"
  }
]

Now when your payment description will look like this:

📘

Merchant Name not set?

If you have a domain configured without merchantName the payID description for that domain will default to the full legal business name used during on-boarding.

Issuing Refunds

Full refunds

Once you have received a payment, and it is in COMPLETE status you can do a full refund by performing an API call like the following, again using the paymentRequestId:

POST https://api.azupay.com.au/v1/paymentRequest/refund?id=a050551479f625c066b559da28fee33c
Authorization: SECR_MYBUSINESSID_myapikey
Content-Type: application/json

You will get a response like the following

{
  "PaymentRequest": {
    "clientId": "MYBUSINESSID",
    "clientTransactionId": "INV-0000001-1",
    "paymentAmount": 32.12,
    "paymentDescription": "Client invoice numner INV-0000001",
    "payID": "[email protected]",
    "paymentExpiryDatetime": "2021-04-21T03:51:45.256Z"
  },
  "PaymentRequestStatus": {
    "paymentRequestId": "a050551479f625c066b559da28fee33c",
    "createdDateTime": "2021-04-21T03:36:45.115Z",
    "payerPaymentDescription": "paying for my goods and services",
    "amountReceived": 32.12,
    "completedDatetime": "2021-04-22T05:07:54.025Z",
    "status": "RETURN_IN_PROGRESS",
    "refundInformation": {
      "availableBalance": "0.00",
      "requests": [
        {
          "refundTrigger": "REFUND_API",
          "createdDateTime": "2021-04-25T23:52:56.189Z",
          "nppTransactionId": "AZTPAU22XXXN20230419100000000000020",
          "status": "IN_PROGRESS",
          "amount": "501.00"
        }
      ]
    }
  }
}

The status of the PaymentRequest will go into RETURN_IN_PROGRESS which means it has been initiated but not completed yet.

After some time, and assuming you have enough liquidity with Azupay to perform the refund, you can enquire about the status for the PaymentRequest and see a change on the status to RETURN_COMPLETE indicating the refund has completed successfully. You will also receive a returnCompletedDatetime.

{
  "PaymentRequest": {
    ...
  },
  "PaymentRequestStatus": {
     ...
    "status": "RETURN_COMPLETE",
    "returnCompletedDatetime": "2021-04-25T23:52:58.189Z",
    "refundInformation": {
      "availableBalance": "0.00",
      "requests": [
        {
          "refundTrigger": "REFUND_API",
          "createdDateTime": "2021-04-25T23:52:56.189Z",
          "completedDateTime": "2021-04-25T23:52:58.189Z",
          "nppTransactionId": "AZTPAU22XXXN20230419100000000000020",
          "status": "COMPLETE",
          "amount": "501.00"
        }
      ]
    }    
  }
}

Because your funds are transferred back to your business regularly, there could be a scenario when you don't
have enough funds to perform the refund. In this case the status of would be RETURN_PENDING_LIQUIDITY and the API will retry the refunds again every 15 minutes until there is enough funds to perform the refund.

Partial refunds

To do a partial refund you would submit a similar request than for full refund but adding a refundAmount query parameter to the request.

Say you have a completed PaymentRequest for $100 and you do a partial refund of $25 using a POST like the
following.

POST https://{{api-host}}/v1/paymentRequest/refund?id=a050551479f625c066b559da28fee33c&refundAmount=25
Authorization: SECR_MYBUSINESSID_myapikey
Content-Type: application/json

Once the refund is completed, when you enquire on the PaymentRequest you will see a response like the one below.

{
  "PaymentRequest": {
    ...
  },
  "PaymentRequestStatus": {
    ...,
    "refundInformation": {
      "availableBalance": "75.00",
      "requests": [
        {
          "refundTrigger": "REFUND_API",
          "nppTransactionId": "AZTPAU22XXXN20230419100000000000020",
          "createdDateTime": "2021-04-22T06:40:25.198Z",
          "completedDatetime": "2021-04-23T05:42:09.373Z",
          "status": "COMPLETE",
          "amount": "25.00"
        }
      ]
    },
    "status": "RETURN_COMPLETE",
    "returnCompletedDatetime": "2021-04-23T05:42:09.373Z",
  }
}

The latest entry in the refundInformation object will contain the information about the partial refund.

👍

Multiple Partial Refund Behaviour

We support multiple partial refunds up to the total amount received. Our system will prevent you refunding more than you have received. Even if you attempt multiple partial refunds and even if your customer sends back partial payments in between we will keep track of the balance and ensure you never send back more than you've received.

Deleting a PayID

When you delete a PaymentRequest the associated PayID will be de-registered from the NPP platform, which means your customers can no longer pay to it. You use the paymentRequestId in a simple HTTP DELETE operation.

DELETE https://api.azupay.com.au/v1/paymentRequest?id=a050551479f625c066b559da28fee33c
Authorization: SECR_MYBUSINESSID_myapikey

📘

When can I delete a Payment Request?

Note: you can only delete a PaymentRequest that is in WAITING status.

Webhooks

We strongly recommend you receive an http call whenever a payment is received and you can do so by passing additional parameters for the endpoint and secret header when creating the PaymentRequest.

POST https://api.azupay.com.au/v1/paymentRequest
Authorization: SECR_MYBUSINESSID_myapikey
Content-Type: application/json
{
  "PaymentRequest": {
    "clientId": "MYBUSINESSID",
    ...
    "paymentNotification": {
      "paymentNotificationEndpointUrl": "https://mybusiness.free.beeceptor.com",
      "paymentNotificationAuthorizationHeaderValue": "my-secret-header"
    }
  }
}

When the payment is completed, you will receive a request like the following:

POST https://mybusiness.free.beeceptor.com
Authorization: my-secret-header
Content-Type: application/json;charset=utf-8
{
  "PaymentRequest": {
    "clientId": "MYBUSINESSID",
    ...
  },
  "PaymentRequestStatus": {
    ...
    "status": "COMPLETE"
  }
}

The contents of the PaymentRequestStatus and PaymentRequest objects are the same as if you were doing a API call to enquire about the PaymentRequest. Notice that the Authorization header is the one you configured in your initial request.

❗️

Authorization header security recommendation

Given your business will probably fulfill a product upon this invocation, for security reasons it is recommended that you use an Authorization header value which is unique per transaction and is a mix of upper and lower alphabetic, numeric and symbol characters.

Now you can use the clientTransactionId or paymentRequestId to match against your records.

👍

Configuring what events to receive via webhook

You can configure which events to receive from the payment lifecycle by going to the Client Dashboard.

Webhooks for Static PayID's

When a customer performs a payment to a Static PayID, the webhook message will contain a message like the following:

{
  "PaymentRequest": {
    "clientId": "MYBUSINESSID",
    ...
  },
  "PaymentRequestStatus": {
    ...,
    "parentPaymentRequestId": "a39c360044a4e399fad93a1c5c9419a5"
    "status": "COMPLETE"
  }
}

Notice there is a parentPaymentRequestId. This corresponds to the paymentRequestId of the original
Static PayID PaymentRequest.

Our PayID statuses

The following is a state diagram for our PayIDs.

StatusDescriptionDynamic PayIDStatic PayID (multipayment = TRUE)
WAITINGThe PayID has been created and is awaiting a payment from your customer. If you created this paymentRequest by setting multiPayment to true then it will remain in WAITING until it's deleted. A Static PayID in WAITING state will expire at the time specified in the paymentExpiryDatetime field.YesYes
COMPLETEThe PayID has been paid.YesNo
RETURN_IN_PROGRESSA payment was made to this PayID and either it's been rejected because it was the incorrect amount or a refund has been requested via API or our Azupay dashboard and the return payment has not yet been completed.YesNo
RETURN_PENDING_LIQUIDITYA payment can only be refunded if there is sufficient liquidity in your Azupay account. Azupay will keep retrying the return of these funds until there is sufficient liquidity from other payments.YesNo
RETURN_COMPLETEA refund was requested and successfully completed.YesNo
RETURN_FAILEDA refund failed due to an unknown error with Azupay. Azupay will retry the return automaticallyYesNo
RETURN_REJECTEDA refund failed due to problems with the destination account. Azupay will not retryYesNo
EXPIREDThe payment was not paid and is past its expiry time or it has been superseded by a new PaymentRequest with the same PayIDYesNo