Skip to content
NovaroPayDocs
PSP-Version 2026-10-25.acacia
Theme
Merchant portal(opens in a new tab)

Webhooks

A webhook endpoint is a URL on your server that we send your account’s events to as they happen: a payment created, processing, succeeded, failed or expired, or given new payment details. You don’t have to ask for a payment’s status: the event tells you. Every event is also kept for 30 days and can be read with GET /events.

Endpoints are set up in the merchant portal, under Settings › Developers › Webhooks, by your account’s admins and developers, or by your account manager. The API has no endpoints for them.

  • The URL is an https URL on a public host name: no IP address, no user name or password. Its path and query are yours; we send to it as it is.
  • Its event types are the ones it gets, or all of them, those we add later too. An endpoint gets only the events of the types it listened to when they happened: changing its types later does not send it earlier events.
  • Each endpoint has its own signing secret, whsec_…. Keep it: you need it to check that a request is ours (Signatures). Roll it in the portal (until its Webhooks page opens, ask your account manager) to get a new one; the old one can keep signing for up to 7 days while you deploy the new one.
  • An account has at most 16 endpoints in each mode.
  • A test mode endpoint gets test mode’s events, a live one live mode’s: the modes never mix.

Each event is one POST to the endpoint, its body the event object as JSON, shaped in the endpoint’s API version (its api_version, or your account’s default):

An event
{
"id": "evt_in_01K7…",
"object": "event",
"type": "payment.succeeded",
"api_version": "2026-10-14.acacia",
"created": 1760000000,
"livemode": false,
"account": "macc_01K7…",
"data": {
"object": { "id": "pay_in_01K7…", "object": "payment", "status": "succeeded", "amount": 49900, … },
"previous_attributes": { "status": "processing" }
},
"request": null,
"pending_webhooks": 1
}

data.object is the object as its GET answers it, right after the event. A body larger than 256 KB is sent without data.object but its id and object: read the object with its GET.

The request’s headers:

Header What it is
PSP-Signature t=<unix time>,v1=<signature>: proves the request is ours (Signatures)
PSP-Event-Id The event’s id
PSP-Delivery-Attempt Which attempt this is, from 1
Content-Type application/json
User-Agent NovaroPay/1.0 (+https://docs…/webhooks)

We send from our IP addresses for your market, if your firewall has to let us in.

  1. Check the signature before anything else (Signatures), on the raw body as it came.
  2. Answer 2xx at once, within 10 seconds, and do the work after. Anything else, a redirect too, is a failure, and we try again.
  3. Process each event once. We send an event at least once: a retry carries the same id and is a duplicate if you processed that id already.
  4. Don’t count on the order. Events can arrive in another order than they happened. Read data.object.status, and data.object.version, which grows with every change of a payment: ignore an event whose version is older than one you have. When in doubt, read the payment with GET /payments/{id}.

An endpoint that is turned off, in the portal or by us, gets nothing, and its retries stop. Events while it is off are not sent once it is on again, and no delivery is made of them: read them with GET /events?created[gte]=<when you turned it off>. delivery_success=false lists only events whose delivery was tried, so it leaves these out.

An endpoint that answered no attempt successfully for 24 hours is failing, and your account’s admins and developers get an email; after 72 hours, and 10 failed attempts at least, we turn it off and email them again. A test mode endpoint is marked and turned off the same way, without the emails. Turn it on in the portal when your server is back (until its Webhooks page opens, ask your account manager), and read the events you missed: those whose delivery failed with GET /events?delivery_success=false, and those of the time it was off with created[gte].

When our support team adds, changes, turns off or on, rolls the signing secret of, rolls back or deletes a live endpoint for you, your account’s admins and developers get an email saying what changed.

A test mode endpoint gets the events of your test payments, as live mode’s would come, so you can build against them: create a test payment and drive it to the status you need with a magic UTR, or a test payout with a magic amount. Test mode retries less: see Retries.