Webhooks are how OwnPay notifies your application of payment events in real time. Rather than polling the API on an interval to check whether a payment has changed status, you register a URL and OwnPay delivers a signed HTTP POST to that URL as soon as the event occurs. This event-driven architecture reduces latency, eliminates unnecessary API calls, and enables your application to react to payment completions, failures, and refunds the moment they happen.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/own-pay/OwnPay-Documentation/llms.txt
Use this file to discover all available pages before exploring further.
How OwnPay Delivers Webhooks
When a payment event occurs — for example, a gateway confirms a successful payment — OwnPay:- Constructs a JSON payload describing the event
- Signs the payload with HMAC-SHA256 using the webhook secret for that brand
- Places the signed request in the delivery queue
- Dispatches an HTTP POST to your registered
callback_urlwithin the same request cycle (or immediately after, via the background queue)
2xx status code within 30 seconds. If it does not, OwnPay considers the delivery failed and schedules a retry.
Automatic Retry Schedule
If your endpoint fails to respond with2xx within 30 seconds, or returns a 4xx / 5xx status, OwnPay retries delivery on the following schedule:
| Attempt | Delay After Previous Failure |
|---|---|
| Retry 1 | 30 seconds |
| Retry 2 | 5 minutes |
| Retry 3 | 30 minutes |
| Retry 4 | 2 hours |
| Retry 5 | 8 hours |
| Retry 6 | 24 hours |
HMAC-SHA256 Signature
Every webhook request includes anX-OwnPay-Signature header containing an HMAC-SHA256 signature of the request body, keyed with your brand’s webhook secret. Verify this signature on every incoming webhook request before processing the payload — this prevents replay attacks and ensures the request genuinely originated from your OwnPay installation.
Signature Verification
The signature is computed as:{timestamp} is the Unix timestamp from the X-OwnPay-Timestamp header and {raw_request_body} is the unparsed JSON string of the request body.
Always use a constant-time comparison function (
hash_equals in PHP, crypto.timingSafeEqual in Node.js, hmac.compare_digest in Python) when comparing signatures. Standard string equality checks are vulnerable to timing attacks.The payment.completed Event Payload
Thepayment.completed event is the most commonly handled webhook event. It fires when a gateway has confirmed successful authorization and OwnPay has recorded the transaction in the ledger.
| Field | Type | Description |
|---|---|---|
type | string | Event type identifier (e.g. payment.completed) |
id | string | Unique event ID — use this for idempotent processing |
created_at | ISO 8601 | When the event was generated |
data.id | string | The OwnPay payment ID |
data.amount | integer | Amount in the smallest currency unit (cents, paisa, etc.) |
data.currency | string | ISO 4217 currency code |
data.status | string | Payment status at time of event |
data.gateway | string | Gateway slug that processed the payment |
data.gateway_transaction_id | string | The processor’s own transaction reference |
data.test | boolean | true if the gateway was in test mode |
data.metadata | object | Custom key-value pairs from the original payment intent |
data.paid_at | ISO 8601 | Timestamp of gateway authorization |
All Event Types
Payment Events
Payment Events
| Event | Fired When |
|---|---|
payment.created | A new payment intent is created |
payment.completed | Gateway confirms successful authorization |
payment.failed | Gateway declines the payment |
payment.refunded | A completed payment is reversed by a refund |
payment.cancelled | Payment is explicitly cancelled before completion |
payment.disputed | A chargeback is initiated by the customer’s bank |
Customer Events
Customer Events
| Event | Fired When |
|---|---|
customer.created | A new customer record is created |
customer.updated | A customer’s details are modified |
customer.deleted | A customer record is removed |
Gateway Events
Gateway Events
| Event | Fired When |
|---|---|
gateway.added | A new gateway is configured on a brand |
gateway.updated | A gateway’s settings are modified |
gateway.removed | A gateway is deleted from a brand |
Configuring Webhooks
Webhooks are configured at the brand level. Navigate to Developers → Webhooks within a brand context and register your endpoint URL.Add a Webhook Endpoint
Go to Developers → Webhooks and click Add Endpoint. Enter your HTTPS URL — webhook endpoints must be publicly accessible and must use HTTPS. Plain HTTP endpoints are not accepted.
Copy the Webhook Secret
After saving, OwnPay displays the webhook secret for this endpoint. Copy it immediately and store it as an environment variable in your application (
OWNPAY_WEBHOOK_SECRET). It is not shown again after you navigate away.Select Events to Subscribe To
By default, all events are delivered to your endpoint. You can filter to specific event types to reduce noise in your handler.
Delivery Logs
OwnPay maintains a full delivery log for every webhook dispatch. To view it:- Admin panel: Go to Developers → Webhooks → Delivery Log
- API:
GET /webhooks/deliveries
pending_retry.
To manually re-trigger a failed delivery:
- Admin panel: Click Retry on the failed delivery row
- API:
POST /webhooks/testswith the original event ID
Testing Webhooks Locally
During development your webhook endpoint is typically running onlocalhost, which is not reachable from the internet. Use a tunneling tool to expose it temporarily:
http://localhost:4040.