Skip to main content
A customer landing on your success page is not proof of payment. Return URLs can be edited, tabs get closed, and mobile networks drop mid-redirect. Confirm every payment on your own server before you release goods, credit, or access. There are two building blocks: webhooks tell you the moment a payment reaches a final state, and the payment endpoint lets you read the current status back whenever you need to double-check.

Webhooks are the source of truth

PayBridgeNP sends a signed webhook the instant a payment reaches a terminal state. This is the reliable, real-time signal to act on. Do not build your fulfillment around the browser redirect.
1

Register an endpoint

Add an HTTPS URL in the Dashboard under Settings → Webhooks, or with the API. Save the signing secret shown once at creation.
2

Verify the signature

Every delivery carries an X-PayBridgeNP-Signature: t=<timestamp>,v1=<hmac> header. Parse out t and v1, compute HMAC-SHA256(signing_secret, "<t>.<raw_request_body>"), and compare the hex digest to v1 in constant time before you trust the payload. Or let the SDK’s constructEvent() do it. Full walkthrough in Verifying webhooks.
3

Act on the event

Fulfill on payment.succeeded, and release any hold on payment.failed. Deliveries are idempotent and can be retried, so key your fulfillment on the payment id and ignore a repeat you have already handled.
Never fulfill an order from return-URL parameters or client-side JavaScript alone. A customer can change them. Fulfill from a signature-verified webhook on your server.

When a payment fails or the buyer cancels

Hosted checkout does not leave the buyer on a dead end. If a payment fails, or the buyer cancels partway through, returning to the same checkout link while the session is still valid brings back the same session at the method picker, with a notice naming the provider that failed and inviting the buyer to try again or pick a different method. The provider that just failed is de-prioritized in the picker rather than pre-selected, so the retry nudges the buyer toward a different route. Because the same session is reused rather than a new one being created, a recovered checkout cannot double-charge: only one attempt on that session can end in a successful payment. The retry does not buy extra time either. The session’s 30-minute expiry window starts at creation, and a failed or cancelled attempt does not extend it. This matters for your webhook handling. A session that simply times out unpaid fires no webhook at all. A buyer-initiated cancellation does fire payment.cancelled, and because a buyer can cancel more than one attempt on the same session before succeeding or giving up, you may receive payment.cancelled more than once for a single session. Treat repeats as informational rather than as a reason to change anything you have already recorded for that session.

Verify before you release value

When a webhook is delayed, or you want a second confirmation before handing over something valuable, read the payment back and check its status yourself. The payment object reports status: "success" once it is paid.
Before you release anything, confirm three things: the status is success, and the amount and currency match what you charged.

Do not poll in a tight loop

Reading the payment endpoint on a fast timer is unreliable and will run into rate limits. Let webhooks do the waiting. Use GET /v1/payments/{id} for a one-off check or to reconcile a specific payment after the fact, not as a polling loop.

Reconciliation

To reconcile a batch against your own records, page through your payments with limit and offset and match each one:
Every payment carries a stable id, status, amount, provider, and provider_ref you can match against your ledger. Page with offset until you have covered the window you care about.