Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.paybridgenp.com/llms.txt

Use this file to discover all available pages before exploring further.

This page explains what happens when a customer places an order, what WooCommerce does with the order status as it moves through the flow, and how PayBridgeNP confirms payment. Read it once and you’ll know which part of the flow to check when something doesn’t behave as expected.

The payment flow

1

Customer places an order and picks PayBridgeNP

The customer reaches your WooCommerce checkout (classic shortcode or Blocks - both work), picks PayBridgeNP as the payment method, and clicks Place order.WooCommerce creates a new order in the pending status and asks the PayBridgeNP gateway to start checkout.
2

Plugin creates a PayBridgeNP checkout session

The plugin:
  • Reads the order total and converts it to paisa (total × 100, rounded)
  • Builds the return and cancel URLs for your store
  • Creates a PayBridgeNP checkout session with the amount, currency (NPR), return URL, cancel URL, and order metadata
  • Records the PayBridgeNP session reference on the order for traceability
  • Adds an order note for support/debugging
If the PayBridgeNP API call fails (bad API key, API down, etc.), the plugin adds a checkout notice with the error message and returns a failure result - the customer sees the error on the checkout page and can try again.On success, WooCommerce redirects the customer’s browser to PayBridgeNP’s hosted checkout.
3

Customer pays on PayBridgeNP's hosted checkout

The customer lands on https://checkout.paybridgenp.com/checkout/cs_..., sees your merchant name and the order total, picks a wallet (eSewa, Khalti, or Fonepay), and completes the payment.
4

Browser return - order → On hold

After the wallet confirms the payment, PayBridgeNP redirects the customer’s browser back to your store with the session reference and success status.The return handler:
  • Validates the order id + order key (using hash_equals to prevent timing attacks and cross-order tampering)
  • If the order is already paid (webhook arrived before the browser), redirects straight to the order-received page
  • Otherwise, moves the order to On hold with a note (“PayBridgeNP: payment submitted, awaiting server confirmation”)
  • Redirects the customer to WooCommerce’s standard order-received page
Why On hold and not Processing? Because the browser return is not authoritative - an attacker could forge a return URL with a valid order key and a fake status=success. The webhook (next step) is the only trustworthy confirmation.
5

Webhook delivery - order → Processing

A few seconds after the wallet confirms the payment, PayBridgeNP sends a signed payment.succeeded webhook to your store.The webhook handler:
  • Reads the raw request body and the X-Paybridge-Signature header
  • Looks up the webhook signing secret from gateway settings - refuses with HTTP 400 if the secret is not configured (no unsigned fallback)
  • Verifies the HMAC-SHA256 signature via the PayBridgeNP PHP SDK’s constructEvent() - rejects forged events and replays older than 5 minutes
  • Extracts the order id from event.data.metadata.order_id
  • Validates the order key from event.data.metadata.order_key against the stored order key (same hash_equals guard as the return handler)
  • Marks the WooCommerce order as paid, which:
    • Sets the order to Processing (or Completed for virtual/downloadable products)
    • Records the PayBridgeNP payment id as the transaction id (visible in WC admin under the order)
    • Reduces stock levels
    • Lets WooCommerce run its normal post-payment notifications and fulfilment hooks
  • Adds an order note recording the provider name, provider reference, and amount
  • Returns HTTP 200 OK

Order state machine

The plugin moves orders through these WooCommerce states:
StateWhenWho sets it
pendingOrder created, customer hasn’t returned from PayBridgeNP yetWooCommerce core
on-holdCustomer returned successfully, webhook hasn’t arrived yetPayBridgeNP return handling
processingWebhook confirmed payment.succeeded, transaction id recordedPayBridgeNP webhook handling
cancelledCustomer clicked cancel on PayBridgeNP’s hosted checkoutPayBridgeNP return handling
failedCustomer returned failed, OR webhook delivered payment.failed / payment.cancelled for an unpaid orderPayBridgeNP return or webhook handling
completedFulfilment complete (virtual/downloadable products auto-complete on payment_complete)WooCommerce core

What the webhook handler does for each event type

EventOrder state (if unpaid)Order state (if already paid)
payment.succeededprocessing through WooCommerce’s normal paid-order flowNo change - idempotent skip
payment.failedfailed with the reason in an order noteNo change - we never un-pay
payment.cancelledfailed with the reason in an order noteNo change - we never un-pay
The is_paid() check before every state transition is the idempotency guard - PayBridgeNP retries webhooks, and we never want a duplicate delivery to accidentally “un-pay” an already-confirmed order.

Block checkout vs classic checkout

Both are supported out of the box. You don’t have to choose one or the other - if your theme uses the classic checkout, the classic gateway renders. If your theme uses the Blocks checkout (the default for stores created since late 2023), the Blocks gateway renders. Both use the same payment flow.

HPOS (High-Performance Order Storage)

The plugin declares HPOS compatibility, so you can enable HPOS in WooCommerce → Settings → Advanced → Features and the plugin will continue to work.

Security model

  • Webhook signature verification is mandatory. The plugin refuses to process webhooks unless the signing secret is configured (HTTP 400 response). There is no unsigned fallback.
  • Order key validation in both the return and webhook handlers prevents an attacker from guessing an order id and forging a success event for someone else’s order.
  • hash_equals comparison for order keys uses a timing-safe string compare.
  • add_query_arg + sanitize_text_field for all incoming query params.
  • wp_unslash on every $_GET / $_SERVER read to undo WordPress’s automatic slash-escaping.
  • No raw SQL anywhere - all order operations go through the WooCommerce CRUD layer.

What’s next