
Editorial illustration.
Originally published 23 June 2023; rewritten and reviewed on 15 October 2026.
The browser returns to a thank-you page, and the order looks complete. That is exactly where a payment integration needs restraint. A navigation event is not a receipt, and an approved order may still require capture before the merchant has a completed payment.
Let the server own the order
Calculate the amount and currency from the application’s trusted records. Create a provider order through a server-side component, keeping credentials outside the browser and source repository.
The archived article used an older SDK pattern. For a new or revised integration, follow the PayPal Orders API documentation for the supported request flow. Confirm the SDK and API version rather than copying historical constructors.
Separate approval, capture and fulfilment
A useful application state machine is:
Local order created
→ Provider order created
→ Buyer approval received
→ Server captures or verifies the payment
→ Expected amount, currency and order identity match
→ Fulfilment is recorded once
Handle declined, pending and cancelled states without pretending they are completed. Keep the provider’s order and capture identifiers alongside the local order.
Make callbacks repeatable
Verify provider notifications using the documented mechanism. A repeated event should find the existing transition rather than ship the order again. A browser return and a webhook may arrive in either order, so they need to converge on the same payment record.
Test duplicate callbacks, timeouts after capture and a mismatch between the expected total and provider data. Separate sandbox credentials and records from live operations.
My preference is to make every payment transition explainable from stored evidence. The thank-you page can then display a result established by the server, instead of becoming the place where success is assumed.