© 2026 Billplz Sdn Bhd

Billplz uses two URL-based mechanisms to notify your system after a payment completes: a server-side callback and a client-side redirect. This article explains how each works, when to use which, and how to avoid common integration mistakes.

For full parameter specs and code examples, see the Payment Completion section in the API documentation.

Before you begin

Callback vs redirect

Billplz sends two notifications after a payment succeeds or fails. They serve different purposes:

Callback callback_url — A server-to-server POST request from Billplz to your backend. This is compulsory for every bill. It guarantees delivery regardless of what happens on the customer's browser, and Billplz retries automatically if your server doesn't respond.

Redirect redirect_url — A client-side browser redirect back to your site. This is optional but recommended. It lets you show customers an instant payment confirmation page. Because it depends on the customer's browser, execution is not guaranteed — the browser may close, the connection may drop, or the app may hang.

Use callback_url as your source of truth for payment status. Use redirect_url to give customers an immediate on-screen confirmation.

How to set up

1. Pass the URLs when creating a bill

You set callback_url and redirect_url as parameters in the Create a Bill API call. They are not configured in the dashboard.

Example request:
curl https://www.billplz.com/api/v3/bills \
  -u {your_secret_key}: \
  -d collection_id="{your_collection_id}" \
  -d email="[email protected]" \
  -d name="Ali Ahmad" \
  -d amount=500 \
  -d description="Order #1234" \
  -d callback_url="https://yourdomain.com/webhook/" \
  -d redirect_url="https://yourdomain.com/payment-complete/"

2. Handle the callback on your server

When payment completes, Billplz sends a POST request to your callback_url with content type application/x-www-form-urlencoded. The body contains the bill's payment status, amount, payer details, and an x_signature for verification.

Your endpoint must respond with HTTP 200 within 20 seconds. Any other status code or a timeout counts as a failed delivery, which triggers retries and degrades your webhook rank.

For the full list of callback parameters, see X Signature Callback URL in the API documentation.

3. Handle the redirect on your frontend

If you provided a redirect_url, Billplz redirects the customer's browser with GET query parameters containing the bill ID, payment status, and an x_signature.

For the full list of redirect parameters, see X Signature Redirect URL in the API documentation.

4. Verify the X Signature

Always verify the x_signature value in both callbacks and redirects to confirm the request came from Billplz and the data has not been tampered with. The process involves sorting the received parameters, constructing a source string, and computing an HMAC-SHA256 hash using your X Signature key.

If the signature matches, you do not need to call the Get a Bill API to confirm payment status — the data is verified.

For step-by-step calculation instructions with sample data, see X Signature Calculation in the API documentation.

Retry behaviour and webhook rank

If your server fails to respond to a callback, Billplz retries up to 4 more times (5 total attempts) on an escalating schedule — starting at ~15 seconds, then two retries ~15 minutes apart, then a final attempt ~24 hours later. After the 5th failure, the callback is permanently removed from the queue. See Basic Callback URL in the API documentation for the exact retry intervals.

Each failed attempt degrades your account's webhook rank by 1 point. Webhook rank controls how quickly Billplz processes your callbacks — 0.0 is the highest priority (default), 10.0 is the lowest. The rank resets daily at 5:00 pm MYT.

Check your current rank with the Webhook Rank endpoint. A consistently high rank means your server is frequently failing to process callbacks — review your endpoint's availability, response time, and status codes.

Testing in sandbox

Your callback_url must point to a publicly accessible URL — localhost addresses do not work because Billplz's servers cannot reach your local machine.

Two common approaches:

Tunnelling service (e.g., ngrok) — Exposes your local server through a public URL. This lets you test your actual callback-handling code end to end.

Webhook testing service (e.g., webhook.site) — Provides a temporary URL that captures and displays incoming requests. Use this to inspect the exact data Billplz sends without writing any server code.

Use your sandbox Secret key and the sandbox base URL (https://www.billplz-sandbox.com/api/). See [Create a sandbox account]() for setup details.

Payment Order callbacks

Payment Order callbacks work differently from bill callbacks. They use a checksum computed with HMAC-SHA512 (not HMAC-SHA256), the callback_url is set at the Payment Order Collection level (not per transaction), and the retry limit is 2 attempts instead of 5.

For full implementation details, see Payment Order Callback in the API documentation.

Common issues