Webhooks
When a payment's status changes, NIXPAY POSTs a signed JSON event to your payment link's
webhook_url.
Payload
code
{
"id": "evt_...",
"type": "payment_link.paid",
"created_at": "2026-07-04T20:00:00Z",
"data": {
"payment_link_id": "pl_...",
"transaction_id": "txn_...",
"status": "paid",
"amount": { "value": "49.95", "currency": "EUR" },
"metadata": { "order_ref": "1234" }
}
}Verify the signature
Every delivery includes a signature header:
code
Nixpay-Signature: t=1783108324,v1=6df2c5...e9v1 is HMAC-SHA256(secret, "<t>.<raw_body>") (hex), where secret is your tenant webhook
secret and <t> is the header timestamp. Recompute it over the raw request body, compare
in constant time, and reject stale timestamps.
Node
code
import crypto from 'node:crypto'
export function verify(secret, header, rawBody, toleranceSec = 300) {
const parts = {}
for (const seg of header.split(',')) {
const [k, v] = seg.split('=')
if (k && v !== undefined) parts[k.trim()] = v.trim()
}
const t = Number(parts.t)
if (!Number.isFinite(t) || t === 0) return false
if (Math.abs(Date.now() / 1000 - t) > toleranceSec) return false
const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex')
const a = Buffer.from(expected)
const b = Buffer.from(parts.v1 ?? '')
return a.length === b.length && crypto.timingSafeEqual(a, b)
}Go
code
func Verify(secret, header string, body []byte, tol int64) bool {
var t, v1 string
for _, p := range strings.Split(header, ",") {
kv := strings.SplitN(p, "=", 2)
if len(kv) == 2 && kv[0] == "t" { t = kv[1] }
if len(kv) == 2 && kv[0] == "v1" { v1 = kv[1] }
}
ts, _ := strconv.ParseInt(t, 10, 64)
if ts == 0 || abs(time.Now().Unix()-ts) > tol { return false }
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(fmt.Sprintf("%s.%s", t, body)))
return hmac.Equal([]byte(hex.EncodeToString(mac.Sum(nil))), []byte(v1))
}Delivery semantics
Return a 2xx to acknowledge. Failed deliveries are retried with exponential backoff and
eventually dead-lettered. Deliveries may be duplicated — dedupe on the top-level event id.