Skip to content

PayUI Integration Guide

This page contains the detailed, step-by-step integration reference for server and client implementation, plus architecture diagrams, event payloads, and error handling guidance.

Steps: Payment Request → OTT → Initialise → Verify

Step 1: Create a Payment Request

Before initialising PayUI, create a Payment Request via the API.

Endpoint: POST /paymentrequests

For complete field documentation, see Create a Payment Request.

Example Request:

{
"reference": "INV-2026-001",
"payment": {
"amount": 3000,
"currencyCode": "AUD",
"description": "Payment for Order #12345"
},
"paymentMethods": [
"card"
],
"transactionRequest": {
"category": {
"frequency": "single",
"captureType": "auto"
}
}
}

Note: Digital wallets are coming soon. When available, Apple Pay requires domain registration. For wallet setup details, see PayUI Digital Wallets.

Response (excerpt):

{
"id": "zWIEEs6BBU2A3GUQ8gD3Ag",
"reference": "INV-2026-001",
"createdDateTime": "2026-01-27T10:15:00Z",
"paymentRequestStatus": "created"
}

Step 2: Generate a One-Time Token (OTT)

Request a one-time token with scope payui and the Payment Request ID from Step 1.

Endpoint: POST /tokens

Example Request:

{
"scope": "payui",
"paymentRequestId": "zWIEEs6BBU2A3GUQ8gD3Ag"
}

Response (excerpt):

{
"token": "eyJhbGciOiJSUzI1NiIsInR5cCI6...",
"tokenType": "onetimetoken",
"scope": "payui",
"expiryDateTime": "2026-01-27T11:15:00Z"
}

Important: tokens are single-use and short-lived. Use expiryDateTime and treat 1 hour as a typical TTL.

Step 3: Configure and Initialise PayUI

Create a minimal configuration object and initialise the PayUI instance on your payment page.

const config = {
token: "your-one-time-token",
containerId: "payment-container",
version: "1.0.0"
}
const payUI = GPAUNZ.PayUI.initialise(config);

Optional UI customisation:

const config = {
token: "your-one-time-token",
containerId: "payment-container",
version: "1.0.0",
ui: {
theme: "light",
variables: {
colorPrimary: "#007ACC",
fontFamily: "Inter, system-ui, -apple-system, \"Segoe UI\", Roboto, Arial, sans-serif",
borderRadius: "8px"
}
}
}

For supported UI options, see PayUI Customisation.

Create the container element in the page:

<div id="payment-container"></div>

Use the initialise event to detect if the form loaded successfully and to present the UI to customers.

End-to-end Transaction Flow (Diagram)

This diagram shows the full PayUI flow from rendering the payment page through to server-side verification.

Note: The diagram uses shorthand GPAUNZ.PayUI.initialise(OTT); in code, pass a config object that includes token, containerId, and version.

sequenceDiagram
    autonumber
    participant FrontEnd
    participant Merchant Server
    participant Single API
    participant PayUI

    FrontEnd->>Merchant Server: Request payment page
    Merchant Server->>Single API: POST /paymentrequests
    Single API-->>Merchant Server: Payment Request ID
    Merchant Server->>Single API: POST /tokens (scope=payui and paymentrequestid)
    Single API-->>Merchant Server: One-Time Token (OTT)
    Merchant Server-->>FrontEnd: Render page with token
    FrontEnd->>PayUI: Load payui.js
    FrontEnd->>PayUI: GPAUNZ.PayUI.initialise(OTT)
    PayUI-->>FrontEnd: Render iframe + emit 'initialise'
    FrontEnd->>FrontEnd: User enters card details
    PayUI-->>FrontEnd: Emit 'surchargeUpdate' (if enabled)
    FrontEnd->>PayUI: User clicks Pay Now
    PayUI->>Single API: Create transaction
    Single API-->>PayUI: Transaction Result and <br/> PaymentRequest state change
    Single API-->>FrontEnd: Emit 'process' event
    FrontEnd->>FrontEnd: Display Processing Result
    alt is recommended
        Single API-->>Merchant Server: Transaction Webhook
        Single API-->>Merchant Server: Payment Request Webhook
    else is polling
        Merchant Server-->>Single API: GET /paymentrequests/{paymentRequestId}
        Single API-->>Merchant Server: paymentRequestStatus + transactionResult/transactionAttempts
        Merchant Server-->>Single API: GET /transactions/{transactionId}
    end

Events (Client-side)

PayUI uses an event-driven architecture. The initialise function returns a PayUIInstance object with on and off methods.

initialise

Fires when PayUI initialisation completes:

payUI.on('initialise', (payload) => {
if (payload.result.status === 'ok') {
console.log('PayUI ready');
} else {
console.error('Initialisation failed:', payload.result.codes);
}
})

surchargeUpdate

Fired when the user enters a valid card number (only if surcharges are enabled):

payUI.on('surchargeUpdate', (payload) => {
if (payload.result.status === 'ok') {
const surcharge = payload.surcharge / 100;
console.log('Surcharge: $' + surcharge.toFixed(2));
}
})

process

Fired when payment processing completes:

payUI.on('process', (payload) => {
if (payload.result.status === 'approved') {
console.log('Transaction ID:', payload.transactionId);
window.location.href = '/success?txn=' + payload.transactionId;
} else {
console.error('Payment failed:', payload.result.codes);
}
})

Important: The process event is for UI feedback only. Always confirm the final outcome server-side (webhooks or GET /transactions/{id}) before fulfilment.

Error Handling

Payment Request Errors

Check result.codes for validation errors when POST /paymentrequests fails. Common issues include invalid amount/currency, missing required fields, or unsupported paymentMethods.

If you are using wallets, ensure your merchant configuration is enabled and the requested methods match what is supported.

Token Generation Errors

If POST /tokens fails, confirm paymentRequestId and that scope is payui. Tokens are single-use and expire at expiryDateTime.

If a token is rejected during initialisation, it may be expired or already used — generate a new token and re‑initialise.

Initialisation Errors

If the initialise event indicates failure:

  • Confirm the PayUI script loaded (no 404s in the console).
  • Confirm containerId matches a real element on the page.
  • Regenerate the token and reload the page if it may be expired or reused.

Processing Errors

If processing fails:

  • Use the process payload for immediate messaging.
  • Call GET /paymentrequests/{id} to determine the outcome and locate the transaction.
  • Fetch the transaction via GET /transactions/{id} for detailed failure codes and final status.

Server-side verification

Critical: The client-side process event is for UI feedback only. Always confirm the final outcome server-side (webhooks or GET /transactions/{id}) before fulfilment.

Transaction type and refunds

PayUI creates a standard purchase transaction.

Refunds follow the normal Transactions API flow using the verified transaction id:

  • POST /transactions/{id}/refunds
  • GET /transactions/{id}/refunds/{refundId}

Create webhook subscriptions via the REST API and listen for transaction and payment request events. Refer to Webhooks for the canonical event names and subscription payload shape.

For webhook creation, signing, and payload details, see: Webhooks.

Note: The sequence diagram below shows example event names for readability. Always follow the Webhooks page for canonical event names. Webhook flow:

sequenceDiagram
    participant GP as GP Gateway
    participant Webhook as Your Webhook Endpoint
    participant DB as Your Database

    GP->>Webhook: POST callbackUrl (X-Signature + JSON payload)
    Webhook->>Webhook: Verify X-Signature (HMAC-SHA256)
    alt signature valid
        Webhook->>Webhook: Parse event and payload
        alt event = 'transactions'
            Webhook->>DB: Persist transaction state
        else event = 'paymentrequests'
            Webhook->>DB: Persist payment request state
        end
        Webhook->>GP: HTTP 200 OK
    else signature invalid
        Webhook->>GP: HTTP 401/403
    end

Option 2: Polling (Fallback)

If webhooks are not feasible, poll from your server after the client receives the process event.

Polling checklist:

  • GET /paymentrequests/{paymentRequestId} — confirm paymentRequestStatus and locate the related transaction
  • GET /transactions/{transactionId} — verify final status and confirm amount/currency

How to locate the transaction to verify:

  • Successful payment: paymentRequestStatus is completed and transactionResult is populated with the transaction id and location.
  • Failed payment: paymentRequestStatus is completed, transactionResult is not populated, and transactionAttempts is populated with the failed transaction (use the id/location from the attempt).

You can also retrieve transactions associated with a payment request via GET /transactions?paymentrequestid={paymentRequestId} and then confirm the final state via GET /paymentrequests/{paymentRequestId}.

Polling flow:

sequenceDiagram
    participant Client as Client Browser
    participant Server as Your Server
    participant API as GP API

    Client->>Server: Send paymentRequestId (and any observed transactionId)
    Server->>API: GET /paymentrequests/{paymentRequestId}
    API-->>Server: Payment Request
    Server->>Server: Extract transactionId from transactionResult/transactionAttempts
    Server->>API: GET /transactions/{transactionId}
    API-->>Server: Transaction
    Server->>Server: Verify payment request completed and amounts match
    Server-->>Client: Return verified result

Testing & Sandbox

PayUI uses the same sandbox environment as the API.

Scenario Triggers

Sandbox scenarios are triggered by specific input values (for example, payment.amount) rather than test card numbers.

For the full list of scenarios and trigger values, see:

Surcharging

To test surcharging, ensure surcharging is enabled on your sandbox merchant account and use the scenario triggers applicable to your configuration.

Wallets

Wallet testing will be available when digital wallets launch. See PayUI Digital Wallets for preparation guidance.

Technical Architecture

Payment Request Lifecycle

stateDiagram-v2
    [*] --> created: POST /paymentrequests
    created --> completed: Transaction Approved
    created --> completed: Transaction Declined
    created --> expired: Expiry time reached
    created --> cancelled: Merchant cancellation
    completed --> [*]
    expired --> [*]
    cancelled --> [*]

Token Lifecycle

stateDiagram-v2
    [*] --> created: POST /tokens
    created --> initialised: PayUI.initialise()
    initialised --> processed: Payment Submitted
    processed --> [*]: Token Used

Note: Tokens expire at expiryDateTime regardless of state (typically 1 hour).

Concurrent Payment Protection

  • Payment Requests are temporarily locked while a payment is processed to avoid duplicate payments.
  • Duplicate idempotency errors return V10018 (header_idempotency_key_is_used).

Examples

For working examples, see: PayUI Examples.