self-hosted payment gateway software

Wiring custom PHP applications to OwnPay via the Merchant API

A step-by-step guide to executing headless checkouts and verifying HMAC webhooks using Laravel and OwnPay's Merchant API.

By Dietrich Rust·September 10, 2026·3 min read
What matters here
  1. The Merchant API enables headless checkouts while keeping payment logic off custom application servers.
  2. Verifying cryptographic signatures on incoming webhooks prevents spoofed transaction completions.
  3. Decoupling custom frontends from gateways isolates core application code from processor API shifts.

The case for decoupled checkout architecture

Building an e-commerce platform or custom subscription service often forces a hard choice. Developers either bolt third-party payment SDKs directly into their core application codebase or hand the entire checkout experience over to expensive hosted SaaS platforms. Both approaches introduce risk. Direct SDK integration litters core repositories with vendor-specific dependencies and compliance burdens. Hosted SaaS pages lock transaction data behind monthly subscriptions and cut into margins.

A headless setup using self-hosted infrastructure solves this friction. By running an AGPL-licensed engine like OwnPay on an isolated PHP server, you separate order orchestration from payment handling. Your main application—whether built on Laravel, Symfony, or custom PHP—handles carts and user profiles. The payment gateway engine handles balance ledgers, processor communication, and transaction states. Evaluating this architecture requires an honest look at comparing payment stacks across SaaS, custom code, and self-hosted deployments.

Step 1: Issuing payment requests via the Merchant API

The integration begins inside your primary PHP application when a customer clicks proceed to checkout. Instead of loading gateway JavaScript bundles directly into your frontend, your application server initiates an authenticated HTTP request to the self-hosted OwnPay REST API.

The Merchant API accepts transaction metadata, including order identifiers, line item totals, and currency codes. Because OwnPay utilizes double-entry bookkeeping at the engine level, every payload creates balanced ledger entries isolating merchant revenue from customer receivables. Your Laravel application dispatches a POST request to your payment endpoint using an HTTP client.

The REST request passes authorization headers along with parameters such as the transaction amount in cents, currency code, order reference, and return URL. The API responds with a structured payment object containing the payment token and checkout URL. If your installation runs a multi-brand configuration, the API resolves the brand context directly from the host request domain or submitted credentials.

Step 2: Directing the customer to the white-label checkout

Once your Laravel application receives the payment object, redirect the customer to the generated checkout URL or embed the checkout flow. Because OwnPay provides complete white-label checkout capabilities, the payment URL reflects your custom domain and branding.

Customers complete their transaction using whichever payment plugin is active on your instance—ranging from standard credit card gateways like Stripe or Braintree to regional processors like SSLCommerz, Nagad, or bKash. The core Laravel application remains completely agnostic to the underlying gateway. If you swap payment processors in the dashboard later, your core application code never changes.

Step 3: Processing cryptographically signed webhooks

Synchronous HTTP redirects are inherently untrusted. A user might close their browser window immediately after payment approval, preventing your return URL from executing properly. Robust headless checkouts rely entirely on asynchronous webhooks for state settlement.

When a transaction settles, OwnPay emits an HMAC-signed webhook event to your designated endpoint. Your Laravel application must capture this payload, compute an HMAC SHA-256 hash using your shared webhook secret, and compare the result against the incoming signature header using a hash-equals comparison. Once verified, the application decodes the JSON payload, checks for the payment completion event, and updates the local order status in the database.

Verifying the cryptographic signature protects your system against forged payment completion signals. For developers extending the payment engine itself, review how to write custom post-payment hooks in OwnPay to trigger internal notifications or run custom server-side scripts before webhooks leave the gateway.

Architectural trade-offs to consider

Deploying a headless payment integration is not without operational commitments. While eliminating platform transaction fees saves substantial capital at scale, self-hosting requires active infrastructure management.

  • Infrastructure redundancy: You must maintain server uptime, run routine database backups, and manage SSL certificates for your gateway instance.
  • Webhook queue delivery: High-volume stores must ensure their Laravel webhook listeners respond quickly to avoid HTTP timeouts, pushing heavy database operations to background queues.
  • Plugin ecosystem alignment: Gateway plugins must be kept updated to ensure compatibility with third-party processor API changes.

For teams seeking full data sovereignty and white-label isolation, coupling Laravel with a dedicated self-hosted payment engine offers an enterprise-grade payment pipeline without vendor lock-in.

More from OwnPay News