self-hosted payment gateway software

Debugging failed payment webhooks on a self-hosted gateway

Trace a webhook from event creation to your endpoint, separate timeouts from bad signatures, and make retries safe to process twice.

By Aria Channing·October 24, 2026·4 min read
What matters here
  1. A webhook timeout means delivery is unconfirmed, not that the payment failed.
  2. Verify signed webhooks against the original request body and the documented signature scheme.
  3. Idempotent handlers prevent retries from creating duplicate orders, credits or fulfillment jobs.

When a payment webhook fails, the first job is to find where the failure happened. A timeout can mean your receiver never responded, the gateway could not reach it, or the response was lost after your code had already acted. Treating every timeout as a failed payment can create duplicate charges or fulfillment. Treating it as success can leave an order stuck.

OwnPay is self-hosted PHP payment gateway software. It provides REST API endpoints and cryptographically signed webhooks, but the exact delivery controls and log locations depend on your installation. Do not assume a particular dashboard, queue screen or retry button exists. Start with the records and logs your deployment actually exposes.

Trace one event end to end

  1. Find the payment record. Use your OwnPay records or API to establish the payment’s current state and identify a stable transaction reference. OwnPay’s double-entry ledger can help confirm whether the payment was recorded; it does not, by itself, prove that your application received a webhook.

  2. Check the sender and receiver logs for the same time window. Look for the event, destination, response status and duration where those details are available. On your PHP server, inspect application and web-server logs. In the receiving application, record the request time, route, response code and processing result. Keep secrets and full payment credentials out of logs.

  3. Compare the two sides. If the sender reports a timeout and your receiver has no matching request, investigate DNS, TLS, routing, firewall rules and server availability. If the receiver logged the request, inspect its response and application error. If it returned success but the sender still reports failure, check whether a proxy or server closed the connection before that response reached the sender.

A timeout is an uncertain delivery result. It does not establish whether the payment itself succeeded or whether your handler completed its work. Check payment state through the available records or API before taking a corrective action.

Separate delivery problems from verification problems

A request that reaches your endpoint but fails signature verification is different from one that never arrives. OwnPay provides cryptographically signed webhooks. Use the signature format and verification procedure documented for your installation; do not guess a header name, algorithm or key source.

Verify the signature against the original request body, before parsing and re-encoding the JSON. Parsing can change whitespace or escaping and therefore change the bytes being checked. Keep the signing secret out of source control and logs. If verification fails, record a redacted diagnostic—such as the request time and a verification-failed result—rather than the secret or sensitive payload.

Do not disable signature checks to make a failing endpoint accept events. First confirm that the endpoint is using the intended secret, that the full request body is available, and that your code follows the documented signing procedure. A valid signature confirms the request’s integrity under that scheme; your application still needs to validate the event fields and decide whether the event is relevant.

Make retries safe

Webhook delivery commonly involves retries when a sender does not receive a timely success response. The exact retry schedule and controls are implementation-specific, so check OwnPay’s documentation and your deployment rather than assuming a retry interval. Design your receiver as if the same event can arrive more than once.

Before applying side effects, store a durable idempotency record keyed by a stable event identifier if one is provided. If the event format has no stable event identifier, use a documented transaction reference and event type only when that combination uniquely identifies the action you need to prevent repeating. Do not deduplicate on amount alone: separate legitimate payments can share an amount.

Make the deduplication check and the business-state update atomic where your storage system allows it. For example, record that an event has been claimed before enqueuing fulfillment, and ensure a repeated delivery sees that record and does not create a second job. Return a success response only after the event is safely recorded for processing. If work takes longer than a webhook request should remain open, persist it for a worker and respond after that handoff succeeds.

Use a controlled recovery path

For a failed payment webhook queue, first establish whether the payment state changed and whether your handler already performed its side effect. Then fix the root cause—such as an unavailable endpoint, slow processing, invalid signature configuration or database error—before replaying or resubmitting anything. If your installation provides a supported retry or replay mechanism, use it only after checking its effect on already-processed events. Otherwise, follow the documented recovery procedure for your setup.

Keep a small record of the event reference, payment reference, failure time, response status and recovery action. That makes it possible to distinguish a transient delivery failure from a broken handler and to reconcile the result later. For server-side capacity and worker considerations, see the deployment guidance on keeping PHP webhook work responsive.

The practical rule is simple: confirm payment state independently, verify the signature before trusting the payload, and make every handler safe to run more than once. Those checks turn an ambiguous timeout into a traceable recovery task instead of a second payment or a missing order.

More from OwnPay News