Payment Requests

This integration guide is designed to help you get started with Volley’s API for embedded or hosted checkout payments.

Payment requests are designed to let you create a page that can be shared with your customers. When a customer wants to accept your request, Volley will redirect them to their banking app to approve and confirm a payment.

Making a Request

You can make a payment request by calling the /requests endpoint.

Request

POST https://api.volley.nz/v1/requests

{
  "bank_account_id": "bankaccount_ZYm2YeJXZ8Vzx3jjMLyp6" // The account which you'll be paid into
  "amount": "1000.00 NZD",     // Up to a maximum of $5000.00
  "message": "Invoice #1234",  // A short message to describe the payment 
  "type": "multi",             // Whether to allow only one, or multiple payments on this request
  "reference": "INV-1234-AB",  // Reference for bank statement, see PCR Fields.
  "merchant_identifier": "..." // A unique identifier matching this request to a record in your system   
}

Response

{
    "request": {
        "id": "request_qTVSdEszuE9jfpTQaJ3j7",
        "type": "single",
        "status": "active",
        "bank_account_id": "bankaccount_ZYm2YeJXZ8Vzx3jjMLyp6",
        "url": "https://app.volley.nz/pay/qTVSdEszuE9jfpTQaJ3j7",
        "message": "Invoice #1234",
        "merchant_identifier": "...",
        "pcr": {
            "reference": "ABC12345678"
        },
        "amount": {
            "formatted": "$1000.00",
            "value": "1000.00 NZD"
        },
        "allow_dynamic_amount": false,
        "min_payment_amount": 50,
        "max_payment_amount": 500000,
        "collect_customer_phone": false,        
        "require_customer_phone": false,
        "require_customer_basic_info": false,
        "require_customer_address": false,
        "allow_marketing_opt_in": false,
        "is_test_mode": false,
        "logo_image_url": "https://images.volley.nz/volley-logo.png",
        "user_id": "user_PB3CbjbM8xdCNALUlC5JQ",
        "created_at": "2025-08-13T11:09:00Z",
        "updated_at": "2025-08-13T11:09:01Z",
        "expires_at": "2025-08-13T11:14:00Z",
    }
}

Bank Accounts

Each payment request you send is associated to a bank account for funds to be paid into. Volley will configure your bank accounts with you during onboarding.

Bank accounts are environment-specific so you’ll need to be aware of what API key you’re calling with. Use the GET /bank-accounts endpoint to find a list of accounts and IDs for your environment.

PCR fields

The New Zealand banking system has three text fields used for providing payment references and other identifiers, particulars, code, and reference, collectively referred to as the PCR fields. These are included on the bank statement lines for both the payee and the payer bank accounts when a payment is made.

Volley uses the particulars and code fields for our own purposes, and you can optionally use the reference field when creating a payment request. This is useful for reconciling payments against your bank account.

Reference

You can provide anything matching [a-zA-Z0-9-]{0,12}

Particulars

Set by Volley.

Code

Always set as “Volley” to help payers identify how they made the payment.

Test Mode

When you use a test environment auth key, your payment requests will be created with is_test_mode set to true. This enables safe testing of your integration without processing real payments.

How Test Mode Works

  • All payments are made to a dedicated test bank account owned by Volley, rather than your business account. We'll configure this test bank account for you during onboarding.

  • You can initiate payments with any of our supported banks, but the actual payment instruction sent to the bank will always be set to $0.01.

  • Any test mode payment request with an amount set to 67.80 NZD will automatically fail all payments made during the bank consent callback.

  • Test mode requests can use our Sandbox bank for payments, labelled as “API Centre”, to test the payment flow easily without needing to use a real bank app.

  • Sandbox login credentials:

    • Username: user01

    • Password: Any password will work.

Payments Lifecycle

When a customer makes a payment, it goes through different statuses so you can track what's happening. Volley will send you status updates via Webhooks at each step so you can respond accordingly.

Most payments follow the happy path of: pending → seen → awaiting-consent → successful. But customers can cancel, banks might have issues, or other things can happen that change the flow. Understanding these statuses helps you handle edge cases and provide better customer experiences.

Status

Description

pending

Payment has been created but the customer hasn't yet started the payment flow

seen

Customer has viewed the payment request, e.g. by scanning the QR code displayed to them

awaiting-consent

Customer has been redirected to their bank and is in the process of approving the payment

successful

Payment has been authorised successfully and funds are being settled to you by the customer’s bank

unconfirmed

Volley was unable to confirm whether this payment was successfully processed or not with the customer’s bank. This is a rare case, but it’s recommended to ask the customer to check on their bank statement to confirm if the payment was made before trying again.

cancelled

Customer or system cancelled the payment before completion

failed

Payment failed due to insufficient funds, technical issues, or bank rejection

refunded

A previously successful payment has been refunded

Payment Tracking

Volley allows for two different models of creating a payment:

  • User created (recommended): You creates a payment request and redirect a customer to it. The payment ID will not be known to your system in advance, but will be identified through webhooks and callbacks. Any failures or cancellations can be retried on the Volley side and may create new payment IDs.

  • Merchant created: You create a payment request and a payment at the same time via the API before redirecting the customer. The payment ID is known to your system in advance. The user will only be able to attempt this exact payment, so any failures or cancellations would need the user to restart the process within your UI.

For payment tracking, you can populate the merchant_identifier field when creating a payment request via the API. This will be persisted on each payment made to that request and returned to you with each completed payment and delivered via webhooks.

Best Practices for Redirects

To prevent misuse of redirect URLs, you should bind the merchant_identifier you provide to Volley with your user’s browser session, e.g. via cookie-based sessions.

After payment completion and redirect back to your success URL, retrieve the payment details via API and verify that the merchant_identifier in the payment record matches the value stored in the user's session. This ensures the payment callback corresponds to the same user who initiated the payment request, preventing attackers from submitting callbacks using payment IDs from other users' transactions.

This verification step should be performed for both user-created and merchant-created payment flows before fulfilling any orders or services.

// In your success_redirect_url handler

app.get('/success', async (req, res) => {
  const { payment_id } = req.query;
  
  // Fetch payment details from your API
  const payment = await paymentGateway.getPayment(payment_id);
  
  // Verify this is for the current payment
  if (payment.merchant_identifier !== req.session.cartId) {
    return res.status(403).send('Invalid payment callback');
  }
  
  // Payment is verified as belonging to this session
  delete req.session.cartId;
  
  // Process the order...
});

Failures and Timeouts

When a payment is cancelled by the user (e.g. in their banking app) Volley will return the customer to the payment request form to try again, with subsequent payments having a new payment ID.

Payment failures will redirect back to your app via the failure_redirect_url.

For timeouts, you can provide an expiration when creating a payment request up to a maximum of 15 minutes (or 10 minutes if using the Embedded Checkout). The request and any non-complete payments will be expired after this time and you’ll receive an update via webhooks. We recommend an expiration time of 5 minutes.

Settlement

Settlement runs over existing Bulk Electronic Clearing System ("BECS") which is the clearing system that operates between banks in New Zealand.

For most cases, payments will complete with funds settled in the recipient account within an hour, 365 days of the year. Payments made after 11pm may be delayed until 9am the following day.