Technical details for OAuth2 Webhook notifications
OAuth2 Webhook Integration Sequence Diagram
Overview
This diagram illustrates how Azupay webhooks integrate with customer-hosted OAuth2 resource servers for secure webhook delivery.
High-Level Sequence Diagram
sequenceDiagram
    participant Azupay as Azupay System
    participant AuthServer as Customer OAuth2 Server
    participant WebhookEndpoint as Customer Webhook Endpoint
    
    Note over Azupay,WebhookEndpoint: Setup Phase (One-time Configuration)
    
    rect rgb(230, 240, 255)
        Note right of Azupay: Customer configures webhook in Azupay Portal
        Azupay->>Azupay: Store webhook config:<br/>- Webhook URL<br/>- OAuth2 Token URL<br/>- Client ID<br/>- Client Secret
    end
    
    Note over Azupay,WebhookEndpoint: Runtime Phase (Per Payment Event)
    
    rect rgb(255, 240, 230)
        Note right of Azupay: Payment event occurs (e.g., payment completed)
        Azupay->>Azupay: Prepare webhook payload
        
        alt No valid access token cached
            Azupay->>AuthServer: POST /oauth/token<br/>grant_type=client_credentials<br/>client_id={id}<br/>client_secret={secret}<br/>scope={optional}
            AuthServer->>AuthServer: Validate credentials
            AuthServer-->>Azupay: 200 OK<br/>{<br/>  "access_token": "eyJhbG...",<br/>  "token_type": "Bearer",<br/>  "expires_in": 3600<br/>}
            Azupay->>Azupay: Cache token until expiry
        end
        
        Azupay->>WebhookEndpoint: POST /webhooks/payments<br/>Authorization: Bearer eyJhbG...<br/>Content-Type: application/json<br/><br/>{payment_data}
        
        WebhookEndpoint->>AuthServer: Validate token (optional)<br/>GET /oauth/introspect or verify JWT locally
        AuthServer-->>WebhookEndpoint: Token valid
        
        WebhookEndpoint->>WebhookEndpoint: Process payment notification
        WebhookEndpoint-->>Azupay: 200 OK<br/>{<br/>  "status": "received"<br/>}
        
        alt Token expired during request
            WebhookEndpoint-->>Azupay: 401 Unauthorized<br/>WWW-Authenticate: Bearer error="invalid_token"
            Azupay->>AuthServer: POST /oauth/token<br/>(Request new token)
            AuthServer-->>Azupay: New access token
            Azupay->>WebhookEndpoint: Retry POST with new token
            WebhookEndpoint-->>Azupay: 200 OK
        end
    end
    
    Note over Azupay,WebhookEndpoint: Retry Logic (On Failure)
    
    rect rgb(255, 230, 230)
        alt Webhook delivery fails
            WebhookEndpoint-->>Azupay: 5xx Error or Timeout
            Azupay->>Azupay: Schedule retry<br/>
            Azupay->>WebhookEndpoint: Retry POST with valid token
        end
    end
Detailed Flow Explanation
1. Setup Phase
The customer configures their webhook endpoint, and supplies this information to Azupay's service desk via an encrypted file:
- Webhook URL: The endpoint where notifications will be delivered
- OAuth2 Token URL: The customer's OAuth2 authorization server token endpoint
- Client Credentials: Client ID and Client Secret for the client_credentials grant
- Optional Scope: Specific scopes required by the customer's authorization server
2. Token Acquisition (Client Credentials Grant)
When Azupay needs to deliver a webhook:
- Azupay checks if it has a valid cached access token for this customer
- If not, Azupay requests a new token from the customer's OAuth2 server
- Azupay caches the token for reuse until it expires (based on expires_in)
3. Webhook Delivery
Azupay delivers the webhook with:
- Authorization Header: Bearer {access_token}
- Content-Type: application/json
- Payload: Payment event data
4. Token Validation
The customer's webhook endpoint can validate the token by:
- JWT Verification: If using JWT tokens, verify signature locally
- Token Introspection: Call OAuth2 introspection endpoint
- Cache Validation: Cache valid tokens to reduce validation overhead
5. Error Handling & Retry
- 401 Unauthorized: Azupay obtains a new token and retries immediately
- 5xx Errors: Azupay retries with exponential backoff
- Timeouts: Treated as delivery failure, scheduled for retry
Example HTTP Requests
Example 1: Token Request (Azupay → Customer OAuth2 Server)
POST /oauth/token HTTP/1.1
Host: auth.customer.com
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
&client_id=azupay_client_abc123
&client_secret=secret_xyz789
&scope=webhook:receiveResponse:
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "webhook:receive"
}Example 2: Webhook Delivery (Azupay → Customer Webhook Endpoint)
Payment Initiation Webhook (Recurring Payments - NPP Direct Entry)
POST /webhooks/payments HTTP/1.1
Host: api.customer.com
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
{
  "PaymentInitiation": {
    "clientId": "YOUR_CLIENT_ID",
    "paymentAgreementId": "K+9p4EE0rJnMtomRfWKWEDRh82BnAboHP2KwgIPyEIA=",
    "paymentAmount": 150.00,
    "clientTransactionId": "invoice-12345",
    "reference": "INVOICE-12345",
    "description": "Monthly subscription payment",
    "paymentInitiationNotification": {
      "notificationUrl": "https://api.customer.com/webhooks/payments",
      "authorizationHeader": "****"
    }
  },
  "PaymentInitiationStatus": {
    "paymentInitiationId": "PI_abc123xyz456",
    "status": "SETTLED",
    "createdDatetime": "2025-10-30T12:34:50Z",
    "completedDatetime": "2025-10-30T12:34:55Z",
    "nppTransactionId": "CUSCAU2S002N20251030000000012345",
    "payerInformation": {
      "bsb": "123456",
      "accountNumber": "12345678",
      "fullLegalAccountName": "John Smith"
    }
  },
  "lastUpdatedTimestamp": "2025-10-30T12:34:55Z"
}Payment Request Webhook (PayTo/PayID - Single Payment)
POST /webhooks/payments HTTP/1.1
Host: api.customer.com
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json
{
  "PaymentRequest": {
    "clientId": "YOUR_CLIENT_ID",
    "clientTransactionId": "TX-abc123xyz",
    "payID": "[email protected]",
    "paymentAmount": 101.95,
    "paymentDescription": "Payment for order #12345",
    "paymentExpiryDatetime": "2025-10-30T13:34:50Z",
    "paymentNotification": {
      "paymentNotificationEndpointUrl": "https://api.customer.com/webhooks/payments",
      "paymentNotificationAuthorizationHeaderValue": "****"
    }
  },
  "PaymentRequestStatus": {
    "paymentRequestId": "86a59da466720f1aabd042ddaee39265",
    "nppTransactionId": "CUSCAU2S002N20251030000000012346",
    "createdDateTime": "2025-10-30T12:34:15Z",
    "completedDatetime": "2025-10-30T12:34:22Z",
    "status": "COMPLETE",
    "amountReceived": 101.95
  }
}Success Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
  "status": "received",
  "message": "Webhook processed successfully"
}Note on Webhook Payload Structure:
- Azupay sends the entire object (PaymentInitiation/PaymentRequest with their status objects)
- The payload structure matches the Azupay API response format for consistency
- Customers can optionally configure "thin payload" mode to receive only essential status fields, however this only applies for PaymentInitiation objects.
Example 3: Token Validation (Customer Webhook → Customer OAuth2 Server)
Option A: Token Introspection
POST /oauth/introspect HTTP/1.1
Host: auth.customer.com
Authorization: Basic Y3VzdG9tZXI6c2VjcmV0
Content-Type: application/x-www-form-urlencoded
token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...Response:
HTTP/1.1 200 OK
Content-Type: application/json
{
  "active": true,
  "scope": "webhook:receive",
  "client_id": "azupay_client_abc123",
  "exp": 1698678896,
  "iat": 1698675296
}Option B: JWT Local Verification (No HTTP Request) The customer's webhook endpoint can verify JWT tokens locally using:
- Public key from JWKS endpoint (.well-known/jwks.json)
- Verify signature, expiration, issuer, and audience claims
- Cache public keys for performance
Example 4: Error Responses
401 Unauthorized (Token Expired):
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer error="invalid_token", error_description="The access token expired"
Content-Type: application/json
{
  "error": "invalid_token",
  "error_description": "The access token has expired"
}429 Rate Limit (Customer Side):
HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json
{
  "error": "rate_limit_exceeded",
  "message": "Too many webhook requests. Please try again later.",
  "retry_after_seconds": 60
}Webhook Event Types
Azupay supports webhooks for multiple entity types. Refer to the relevant API routes for information on what events are supported.
Customer Implementation Requirements
OAuth2 Authorization Server Must Support:
- Client Credentials Grant (RFC 6749 Section 4.4)
- Token Endpoint with standard request/response format
- Token Expiration via expires_inparameter
- Optional: Token introspection endpoint (RFC 7662)
- Optional: JWKS endpoint for JWT verification
Webhook Endpoint Must:
- Validate Bearer Token on every request
- Return appropriate HTTP status codes:
- 200 OK: Successfully processed (required for Azupay to stop retrying)
- 401 Unauthorized: Invalid/expired token (Azupay will get new token and retry)
- 429 Too Many Requests: Rate limited (Azupay will retry with backoff)
- 5xx: Server error (Azupay will retry with exponential backoff)
 
- Process webhooks idempotently (same webhook may be delivered multiple times)
- Respond quickly (Azupay has 5 second timout)
- Parse the entity type by checking for PaymentRequest,PaymentInitiation,PaymentAgreement, orPaymentAgreementAmendmentkeys
Security Best Practices:
- Use HTTPS for all endpoints (OAuth2 and webhooks)
- Implement rate limiting to prevent abuse
- Monitor token usage for suspicious activity
- Rotate client secrets periodically
- Use short-lived tokens (15-60 minutes recommended)
- Log all webhook deliveries for audit purposes
Configuration Example
Azupay supports configuration customisations on Webhooks. Note that webhooks using OAuth2 are configured at the client level and can not be configured per transaction. This currently requires a manual configuration by the Azupay service desk team.
{
  "webhook_config": {
    "id": "oauth2-webhook-example",
    "url": "https://api.customer.com/webhooks/payments",
    "securityType": "OAUTH2",
    "oauth2": {
      "tokenUrl": "https://auth.customer.com/oauth/token",
      "oauthClientId": "azupay_client_abc123",
      "oauthClientSecret": "secret_xyz789",
      "oauthScope": "webhook:receive",
      "sendClientCredentialsIn": "BODY"
    },
    "webhooksOn": [
      "PaymentRequest.COMPLETE",
      "PaymentRequest.WAITING"
    ],
    "thinPayload": false
  },
  "retry_policy": {
    "max_attempts": 18,
    "initial_delay_seconds": 20,
    "retry_delay_seconds": 900
  }
}Configuration Options:
- securityType: Can be OAUTH2orHEADER(for simple bearer token)
- sendClientCredentialsIn: BODY(form data) orHEADER(Basic auth)
- thinPayload: If true, sends only essential fields (ID and status) to reduce payload size. Note this configuration only applies for PaymentInitiation type objects.
- webhooksOn: Array of event types to trigger this webhook
- Retry behavior: After 3 attempts every 20 seconds, Azupay waits 900 seconds (15 minutes) between retries. Azupay can limit the amount of retries we will attempt against your system if required.
Benefits of OAuth2 Integration
- Enhanced Security: Token-based authentication with expiration
- Centralised Auth Management: Customer controls access via their OAuth2 server
- Token Rotation: Automatic token refresh without webhook reconfiguration
- Audit Trail: OAuth2 server logs all token requests
- Scalability: Single OAuth2 server can protect multiple webhook endpoints
- Standards-Based: Industry-standard protocol (RFC 6749)
- Revocation Support: Customers can revoke access by invalidating client credentials
Notes
- Azupay maintains token caching to minimize requests to customer OAuth2 servers
- Token refresh happens automatically before expiration when possible
- Webhooks should be treated as untrusted, and event statuses should be independently verified via a GET request for the associated transaction.
- Customers should implement monitoring on their OAuth2 and webhook endpoints
- Implement idempotency using the unique IDs in the payload to prevent duplicate processing
- Consider implementing timestamp-based replay protection on your webhook endpoint
Updated about 6 hours ago
