PayTo Integration Guide

Step-by-step instructions for integrating PayTo recurring payments with Azupay

Azupay PayTo Integration Guide

Overview

This guide provides step-by-step instructions for integrating with Azupay's PayTo payment system. PayTo enables recurring payments through pre-approved payment agreements between payers and merchants, providing a secure and efficient way to collect recurring payments.

Prerequisites

Before you begin, ensure you have:

  • Valid Azupay API credentials (Secret Key and Client ID)
  • Access to either UAT (https://api-uat.azupay.com.au/v1) or Production (https://api.azupay.com.au/v1) environment
  • Webhook endpoint configured for receiving payment status updates
  • Understanding of your payment flow requirements
  • Ability to instruct payers to access their banking app or online banking for PayTo agreement approvals

Authentication

All API calls require authentication using your Secret Key in the Authorization header:

Authorization: SECR_${your-client-id}_${your-secret-key}

You can obtain your API keys from the Azupay Client Dashboard. Navigate to the API Keys section to generate and manage your authentication credentials.

Understanding PayTo Approval Process

PayTo agreements require approval directly in the payer's banking app or online banking portal. This is a regulatory requirement that ensures payers have direct control over payment agreements with their bank.

What Happens During Approval:

  1. After creating a payment agreement via API, the agreement appears as "pending approval" in the payer's banking interface
  2. The payer logs into their banking app/website and navigates to the PayTo section
  3. The payer reviews the agreement details (amount limits, frequency, merchant details)
  4. The payer approves or rejects the agreement
  5. Once approved, Azupay receives notification from the bank and sends you a webhook

Instructions for Your Payers:

When you create a payment agreement, inform your payers to:

  1. Open their banking app or log into online banking
  2. Look for "PayTo" or "Payment Agreements" section
  3. Find the pending agreement from your business
  4. Review and approve the agreement

PayTo Payment Flow

PayTo agreements enable recurring payments by establishing a pre-approved payment mandate between the payer and your business.

sequenceDiagram
    actor Payer as Payer
    participant Merchant as Merchant
    participant API as Azupay API
    participant Bank as Bank

    Payer ->> Merchant: start transaction

    opt Create and Approve Agreement (if it hasn't been created)
        Merchant ->> API: POST /paymentAgreement<br>{PaymentAgreement: {clientTransactionId...}}
        API ->> Merchant: 201 CREATED<br>{PaymentAgreementStatus: {paymentAgreementId,...}}
        Payer -->> Bank: Approve payment Agreement
        Bank -->> API: agreement approved
        API -->> Merchant: POST /{webhook}<br>{PaymentAgreementStatus: {status:ACTIVE}}
    end

    opt Amend the Agreement (if maximumAmount or frequency need to change)
        Merchant ->> API: POST /paymentAgreement/amendment<br>{PaymentAgreementAmendment: {clientTransactionId, agreementDetails: {...}}}
        API ->> Merchant: 201 CREATED<br>{PaymentAgreementAmendmentStatus: {amendmentStatus: PENDING}}
        Payer -->> Bank: Approve payment Agreement Amendment
        Bank -->> API: agreement amendment approved
        API -->> Merchant: POST /{webhook}<br>{PaymentAgreementAmendmentStatus: {status:COMPLETED}}
    end

    Merchant ->> API: POST /paymentInitiation<br>{PaymentInitiation: {paymentAmount: 12.33, paymentAgreementId, clientTransactionId...}}
    API ->> Merchant: 201 CREATED<br>{PaymentInitiationStatus: {status: CREATED}}
    Bank -->> API: initiation completed
    API -->> Merchant: POST /{webhook}<br>{PaymentInitiationStatus: {status:SETTLED}}

    Merchant ->> Payer: product fulfilment<br> or payment confirmation
📚

API Documentation:

Step 1: Create Payment Agreement (Optional - if not exists)

If you don't have an active payment agreement for the customer, create one first.

Endpoint: POST /paymentAgreement

Request Payload:

{
  "PaymentAgreement": {
    "clientId": "CLIENT1",
    "clientTransactionId": "TX-AGR-001-20241201-001",
    "contractId": "CONTRACT-12345-MONTHLY",
    "payerDetails": {
      "name": "Jane Smith",
      "type": "Person",
      "payIDDetails": {
        "payID": "[email protected]",
        "payIDType": "EMAIL"
      }
    },
    "paymentAgreementType": "OTHER SERVICE",
    "description": "Monthly subscription payment",
    "agreementDetails": {
      "variableAgreementDetails": {
        "startDate": "2024-12-01",
        "endDate": "2025-12-01",
        "maximumAmount": "100.00",
        "frequency": "MONTHLY"
      }
    },
    "agreementExpiryMinutes": 1440
  }
}

Response:

{
  "PaymentAgreementStatus": {
    "paymentAgreementId": "K+9p4EE0rJnMtomRfWKWEDRh82BnAboHP2KwgIPyEIA=",
    "status": "CREATED",
    "createdDatetime": "2024-12-01T10:00:00.000+11:00"
  }
}

Step 2: Payer Approves Agreement

Once the payment agreement is created, instruct the payer to check their banking app or online banking to approve the PayTo agreement. The payer will see a notification or pending agreement in their banking interface that they need to approve. Once approved, you'll receive a webhook notification.

Webhook Notification (Agreement Approved):

{
  "PaymentAgreementStatus": {
    "paymentAgreementId": "K+9p4EE0rJnMtomRfWKWEDRh82BnAboHP2KwgIPyEIA=",
    "status": "ACTIVE",
    "createdDatetime": "2024-12-01T10:00:00.000+11:00",
    "registrationDatetime": "2024-12-01T10:15:00.000+11:00"
  }
}

Step 3: Amend Agreement (Optional - if maximum amount needs change)

If you need to modify the agreement (e.g., change maximum amount), create an amendment. The payer will need to approve the amendment in their banking app.

Endpoint: POST /paymentAgreement/amendment

Request Payload:

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

Response:

{
  "PaymentAgreementAmendmentStatus": {
    "paymentAgreementAmendmentId": "L+8q3FF1sKoNuqnSgXLXFESi93CoBcpIQ3LxhJQzFJB=",
    "amendmentStatus": "PENDING",
    "createdDatetime": "2024-12-01T11:00:00.000+11:00"
  }
}

Step 4: Initiate Payment

Once the agreement is active, initiate payments against it.

Endpoint: POST /paymentInitiation

Request Payload:

{
  "PaymentInitiation": {
    "clientId": "CLIENT1",
    "paymentAgreementId": "K+9p4EE0rJnMtomRfWKWEDRh82BnAboHP2KwgIPyEIA=",
    "clientTransactionId": "TX-PMT-001-20241201-001",
    "paymentAmount": "75.50",
    "description": "December subscription payment",
    "reference": "SUB-DEC-2024"
  }
}

Response:

{
  "PaymentInitiationStatus": {
    "paymentInitiationId": "M+7r2GG0tLpOvroPhaYYGFTj04DpCdqJR4MyiKRzGKC=",
    "status": "CREATED",
    "createdDatetime": "2024-12-01T12:00:00.000+11:00"
  }
}

Step 5: Receive Settlement Webhook

When the payment settles, you'll receive a webhook notification.

Webhook Notification (Payment Settled):

{
  "PaymentInitiationStatus": {
    "paymentInitiationId": "M+7r2GG0tLpOvroPhaYYGFTj04DpCdqJR4MyiKRzGKC=",
    "status": "SETTLED",
    "createdDatetime": "2024-12-01T12:00:00.000+11:00",
    "completedDatetime": "2024-12-01T12:05:00.000+11:00",
    "nppTransactionId": "FTI202412011205001"
  }
}

Payment Status Values

PaymentAgreement Status:

  • CREATED - Agreement created, awaiting customer approval in their banking app
  • ACTIVE - Agreement approved and active
  • SUSPENDED - Agreement temporarily suspended
  • CANCELLED - Agreement cancelled
  • FAILED - Agreement creation failed

PaymentInitiation Status:

  • 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.

Webhook Security

For comprehensive webhook security information, refer to the Azupay Webhooks Documentation.

Validating Webhooks

Always validate webhook authenticity by checking the Authorization header against your configured webhook secret. Consider implementing additional security measures:

// Example webhook validation
function validateWebhook(req) {
  const expectedAuth = 'Bearer your-webhook-secret';
  const receivedAuth = req.headers.authorization;

  return expectedAuth === receivedAuth;
}

IP Whitelisting

Implement IP whitelisting to ensure webhooks only come from trusted Azupay servers. Add these security measures to your webhook endpoint:

// Example IP whitelisting for webhook security
function isValidAzupayIP(clientIP) {
  // Contact Azupay support to get the current list of webhook IP addresses
  const azupayWebhookIPs = [
    // Add Azupay's webhook IP addresses here
    // Example: '203.0.113.1', '203.0.113.2'
  ];

  return azupayWebhookIPs.includes(clientIP);
}

function validateWebhookSecurity(req) {
  const clientIP = req.connection.remoteAddress || req.socket.remoteAddress;
  const authHeader = req.headers.authorization;

  // Check both IP and authorization
  return isValidAzupayIP(clientIP) &&
         authHeader === 'Bearer your-webhook-secret';
}
⚠️

Important: Contact Azupay support to obtain the current list of webhook source IP addresses for your environment (UAT/Production).

Webhook Retry Logic

Azupay will retry webhook deliveries if your endpoint returns a non-2xx status code. Ensure your webhook endpoint:

  • Returns 2xx status codes for successful processing
  • Is idempotent to handle duplicate deliveries
  • Processes webhooks quickly (< 10 seconds)

Best Practices

1. Idempotency

Always use unique clientTransactionId values to prevent duplicate transactions. If the same ID is used, the API will return the existing transaction instead of creating a duplicate.

2. Webhook Security

Validate webhook authenticity using the Authorization header you configured. Consider implementing webhook signature verification for additional security.

3. Error Handling

Implement robust error handling for network timeouts, API errors, and invalid responses. Use exponential backoff for retrying failed requests.

4. Status Monitoring

Monitor payment statuses regularly and handle edge cases like expired payments or failed settlements appropriately.

5. Testing

Use the UAT environment (https://api-uat.azupay.com.au/v1) for thorough testing before production deployment.

6. Logging

Log all API requests and responses (excluding sensitive data) for debugging and audit purposes.