Pay & Subscribe Checkout

Comprehensive guide for setting up subscription payments and agreements using Pay & Subscribe checkout

Overview

The PayTo Pay & Subscribe checkout feature lets merchants set up subscription payments with customers through a three-step integration. First, merchants enable Checkout App with PayTo in their dashboard. Next, they create a payment request with initial and recurring payment details, then redirect customers to the Azupay checkout URL to authorize the immediate payment and ongoing agreement via PayTo. After completion, merchants receive a paymentAgreementId via API polling or webhook, representing the customer's payment mandate. Finally, merchants use this ID to initiate recurring payments at set intervals (weekly, monthly, or annually) without further customer action. Merchants should monitor the payment agreement status (ACTIVE, CANCELLED, or SUSPENDED) since customers can manage agreements anytime through their banking app.

Integration Guide

The PayTo Pay & Subscribe checkout feature lets merchants set up subscription payments with customers through a three-step integration. First, merchants enable Checkout App with PayTo in their dashboard. Next, they create a payment request with initial and recurring payment details, then redirect customers to the Azupay checkout URL to authorize the immediate payment and ongoing agreement via PayTo. After completion, merchants receive a paymentAgreementId via API polling or webhook, representing the customer's payment mandate. Finally, merchants use this ID to initiate recurring payments at set intervals (weekly, monthly, or annually) without further customer action. Merchants should monitor the payment agreement status (ACTIVE, CANCELLED, or SUSPENDED) since customers can manage agreements anytime through their banking app.

Part 1: Dashboard Configuration

Enable Checkout App v3 with PayTo

Before using the PayTo Subscribe feature, you must enable the checkout app v3 with PayTo functionality in your dashboard.

  1. Access Dashboard: Log into your Azupay merchant dashboard
  2. Navigate to Apps: Go to the Apps section
  3. Enable Checkout v3: Find and enable the "Checkout" App
  4. Configure PayTo: Ensure PayTo functionality is enabled in the app settings
  5. Optional Settings: Choose a default landing product for when your checkout does not require a recurring agreement.

Part 2: Create Payment Request and Redirect Customer

Creating a Payment Request with Subscription

To create a payment request that includes subscription setup, include the following fields in your payment request:

Required Fields:

  • clientId: Your client identifier
  • clientTransactionId: Unique transaction identifier
  • paymentAmount: Initial payment amount
  • paymentDescription: Description of the payment
  • recurringPaymentAmount: Amount for recurring payments
  • recurringPaymentFrequency: Payment frequency
  • recurringPaymentEndDate: The date after which the agreement will expire in yyyy-mm-dd format. The Agreement will not have an end date if not provided.
  • recurringPaymentType: Determines the type of Agreement. Default is VARIABLE when not provided.
    • FIXED: Future recurring payments must be of exactly recurringPaymentAmount.
    • VARIABLE: Future recurring payments can be of equal or less than recurringPaymentAmount
📘

When both the recurringPaymentAmount and recurringPaymentFrequency are provided in the request, the Checkout UX will remove the PayID option and will only enable PayTo checkout. If neither is provided then it will present the UX depending what was configured in the Client Dashboard Apps Settings.

Supported Frequencies

  • DAILY - Daily recurring payments
  • WEEKLY - Weekly recurring payments
  • MONTHLY - Monthly recurring payments
  • ANNUAL - Annual recurring payments
  • ADHOC - Any time recurring payments.
⚠️

Just be aware that choosing ADHOC Frequency might lead to agreements been denied by banks due to maximum amount restrictions.

API Endpoint: Create Payment Request

POST /paymentRequest

Headers:

Authorization: your-api-key
Content-Type: application/json

Request Body:

{
  "PaymentRequest": {
    "clientId": "your-client-id",
    "clientTransactionId": "unique-transaction-id",
    "paymentAmount": 100.00,
    "recurringPaymentAmount": 50.00,
    "recurringPaymentFrequency": "ANNUAL",
    "recurringPaymentType": "VARIABLE",
    "recurringPaymentEndDate": "2026-11-04",
    "paymentDescription": "Annual subscription setup",

    "paymentNotification": {
      "paymentNotificationEndpointUrl": "https://my-webhook.merchantname.com",
      "paymentNotificationAuthorizationHeaderValue": "webhook-secret"
    }
  }
}

Response:

{
  "PaymentRequest": {
    "clientId": "your-client-id",
    "clientTransactionId": "unique-transaction-id",
    "paymentAmount": 100.00,
    "recurringPaymentAmount": 50.00,
    "recurringPaymentFrequency": "ANNUAL",
    "recurringPaymentType": "VARIABLE",
    "recurringPaymentEndDate": "2026-11-04",
    "paymentDescription": "Annual subscription setup",
    "checkoutUrl": "https://pay.azupay.com.au/xxxx/pay"
  },
  "PaymentRequestStatus": {
    "paymentRequestId": "abc123",
    "status": "WAITING",
    "createdDateTime": "2024-01-15T10:30:00Z"
  }
}

Redirect Customer to Checkout

Once you receive the response, redirect your customer to the checkoutUrl from the response:

If you are not embedding this checkoutUrl inside an iframe on your checkout app then provide the following additional query parameters to the checkout url:

  • redirectURL: the url that a successful transaction should be redirected to.
  • cancelRedirectURL: the url that an unsuccessful transaction should be redirected to.
const checkoutUrl = response.PaymentRequest.checkoutUrl;

// Create a URL object
const url = new URL(checkoutUrl);

// Add your redirect URLs
url.searchParams.set("redirectURL", "https://example.com/success");
url.searchParams.set("cancelRedirectURL", "https://example.com/cancel");

// Redirect
window.location.href = url.toString();

Obtaining the Payment Agreement ID

After successful payment, you can obtain the paymentAgreementId in two ways:

Get Payment Request Status

GET /paymentRequest?id={paymentRequestId}

Response:

{
  "PaymentRequest": {
    "clientId": "your-client-id",
    "clientTransactionId": "unique-transaction-id",
    "paymentAmount": 100.00,
    "recurringPaymentAmount": 50.00,
    "recurringPaymentFrequency": "ANNUAL",
    "paymentDescription": "Annual subscription setup",
    "checkoutUrl": "https://pay.azupay.com.au/xxxx/pay"
  },
  "PaymentRequestStatus": {
    "paymentRequestId": "abc123",
    "status": "COMPLETE",
    "createdDateTime": "2024-01-15T10:30:00Z",
    "completedDatetime": "2024-01-15T10:35:00Z",
    "settledBy": "PayTo",
    "paymentAgreementId": "agreement-456"
  }
}

Webhook Notification

If you defined paymentNotification details in the PaymentRequest or you have global webhook configuration setup, you'll receive a notification with the payment status including the paymentAgreementId:

Webhook Endpoint:

POST https://my-webhook.merchantname.com/

Headers:

Authorization: webhook-secret
Content-Type: application/json

Webhook Body:

{
  "PaymentRequest": {
    "clientId": "your-client-id",
    "clientTransactionId": "unique-transaction-id",
    "paymentAmount": 100.00,
    "recurringPaymentAmount": 50.00,
    "recurringPaymentFrequency": "ANNUAL",
    "paymentDescription": "Annual subscription setup",
    "checkoutUrl": "https://pay.azupay.com.au/xxxx/pay"
  },
  "PaymentRequestStatus": {
    "paymentRequestId": "abc123",
    "status": "COMPLETE",
    "createdDateTime": "2024-01-15T10:30:00Z",
    "completedDatetime": "2024-01-15T10:35:00Z",
    "settledBy": "PayTo",
    "paymentAgreementId": "agreement-456"
  }
}

Part 3: Payment Agreement Details and Recurring Payments

Payment Agreement Structure

When a subscription payment request is completed, a payment agreement is created with the following structure:

{
  "PaymentAgreement": {
    "payerDetails": {
      "name": "John Doe",
      "payIDDetails": {
        "payID": "[email protected]",
        "payIDType": "EMAIL"
      }
    },
    "agreementDetails": {
      ... This depends on the parameters provided to the paymentRequest
    }
  },
  "PaymentAgreementStatus": {
    "status": "ACTIVE"
  }
}

If you provided recurringPaymentType of FIXED then the Agreement details will look like the following. The firstPaymentAmount will correspond to the amount of the Payment Request.

{
  ...
  "agreementDetails": {
    "fixedAgreementDetails": {
      "firstPaymentAmount": "100.00",
      "amount": "50.00",
      "frequency": "ANNUAL",
      "endDate": "2024-05-06"
    }
  }
}

Otherwise, if the recurringPaymentType is VARIABLE then the Agreement details will look something like this.

{
  ...
  "agreementDetails": {
    "variableAgreementDetails": {
      "maximumAmount": "200.00",
      "frequency": "ANNUAL",
      "endDate": "2024-05-06"
    }
  }
}

Agreement Properties

  • firstPaymentAmount: The initial payment amount that was processed. Only for FIXED type.
  • amount: The recurring payment amount for future payments. Only for FIXED type
  • maximumAmount: The maximum amount that can be withdraw. Only for the VARIABLE types.
  • frequency: The payment frequency (WEEKLY, MONTHLY, ANNUAL)
  • endDate: Null for open-ended
  • status: Agreement status (ACTIVE, CANCELLED, EXPIRED)

Agreement Status

The payer might suspend or cancel the agreement at any time.

Checking for ACTIVE agreement status before initiating a payment is desired.

  • ACTIVE - Agreement is active and ready for recurring payments
  • CANCELLED - Agreement has been cancelled by the payer on their banking app.
  • SUSPENDED - Agreement has been suspended by the payer on their banking app.

Initiating Recurring Payments

To initiate a recurring payment using the payment agreement after the first period has elapsed, use the payment initiation endpoint:

POST /paymentInitiation

Headers:

Authorization: your-api-key
Content-Type: application/json

Request Body:

{
  "PaymentInitiation": {
    "paymentAgreementId": "agreement-456",
    "paymentDescription": "Monthly subscription payment",
    "clientTransactionId": "recurring-payment-789",
    "paymentInitiationNotification": {
      "endpointURL": "https://my-webhook.merchantname.com",
      "authorizationHeader": "webhook-secret"
    }
  }
}

Response:

{
  "PaymentInitiation": {
    "paymentAgreementId": "agreement-456",
    "paymentDescription": "Monthly subscription payment",
    "clientTransactionId": "recurring-payment-789"
  },
  "PaymentInitiationStatus": {
    "paymentInitiationId": "initiation-123",
    "status": "WAITING",
    "createdDateTime": "2024-02-15T10:30:00Z"
  }
}

You can wait for a webhook notification with the status of SETTLED for the paymentInitiation on the endpointURL you provided when the paymentInitiation was created.

PaymentInitiation Statuses

  • CREATED - Payment instruction created
  • PENDING - Payment processing in progress
  • SETTLED - Payment completed successfully
  • FAILED - Payment failed
  • RETURN_IN_PROGRESS - Refund in progress
  • RETURN_COMPLETE - Refund completed successfully
  • RETURN_FAILED - Refund failed

Additional PayTo Features

Agreement Management

Search Payment Agreements

Endpoint: POST /paymentAgreement/search

Search for payment agreements based on various criteria such as:

  • Payment agreement ID
  • Contract ID
  • Date range (from/to dates)

Example Request:

{
  "PaymentAgreementSearch": {
    "paymentAgreementId": "K+9p4EE0rJnMtomRfWKWEDRh82BnAboHP2KwgIPyEIA="
  }
}

Amend Agreement

Endpoint: POST /paymentAgreement/amendment

Create amendments to existing payment agreements to modify details like maximum amount or frequency.

Example Request:

{
  "PaymentAgreementAmendment": {
    "clientTransactionId": "TX-AMD-001-20241201-002",
    "paymentAgreementId": "K+9p4EE0rJnMtomRfWKWEDRh82BnAboHP2KwgIPyEIA=",
    "agreementDetails": {
      "variableAgreementDetails": {
        "maximumAmount": "200.00",
        "frequency": "FORTNIGHTLY"
      }
    }
  }
}

Payment Initiation Management

Search Payment Initiations

Endpoint: POST /paymentInitiation/search

Search for payment initiations based on various criteria like client transaction ID or date range.

Example Request:

{
  "PaymentInitiationSearch": {
    "clientTransactionId": "TX-PMT-001-20241201-001"
  }
}

Refund Payment Initiation

Endpoint: POST /paymentInitiation/refund

Initiate a refund for a completed payment initiation.

Test Data

Test PayID Values for successful transactions:

Best Practices

Security

  • Always validate with the backend that the transaction has been completed either with the webhook or the API.
  • Provide a secret header for the webhook and validate it.

Other

  • Do not append query parameters to the checkoutUrl use a proper url parsing tool to prevent the code to break if the url changes.
  • Checking for ACTIVE agreement status before initiating a payment and notify the payer if required.

Additional Information

See the documentation on each of the APIs for more information on all statuses and features