Skip to main content
When an invoice changes status, PawPayments POSTs an invoice snapshot (JSON) to the merchant’s notify_url (per-invoice override) or to the merchant-level callback_url. Delivery is automatic and idempotent — every merchant receives at most one webhook per terminal transition of each invoice.

Delivery guarantees

  • Automatic. Fires on every status change of an invoice created via POST /api/v2/invoices (and on auto-created invoices bound to permanent addresses).
  • Persistent retries. Delivery attempts run as a durable background job, so they survive process restarts. On 2xx → done. On 4xx (except 408/425/429) → give up immediately (merchant is presumed misconfigured). Otherwise the job is retried with exponential backoff: 30s, 1m, 2m, 5m, 10m, 20m, 40m, 80m, 160m — up to 10 attempts total (≈5h wall-clock).
  • URL safety. Each attempt DNS-resolves the callback and refuses to deliver if the host is private, loopback, link-local, or unresolvable. These refusals are logged as attempts too (with a human-readable reason).
  • Source IPs. All webhooks originate from the subnet 94.249.204.0/24. Allowlist this range if your endpoint is firewalled or restricted to known senders.
  • Audit log. Every delivery attempt is recorded: URL, status code, response body (first 500 chars), attempt number, and timestamp. Inspect via GET /api/v2/notifications or replay a specific invoice on demand via POST /api/v2/invoices/{id}/notify.

Headers

Payload

The payload is the same invoice shape returned by GET /api/v2/invoices/{id} (see the API Reference for the canonical schema). Authenticity is established exclusively by the X-Paw-Signature header — there is no signature field inside the JSON body. Key fields for merchant processing: A finalised webhook (success, paid_over, failed, high_risk, cancelled) carries the authoritative payment state — treat it as the source of truth and disregard any earlier confirming / partially_paid deliveries for the same invoice.

Verification (Node.js)

Important: verify against the raw request body before JSON-parsing. Any whitespace / key-reordering will produce a different signature.

Verification (PHP)

Replay and introspection

  • POST /api/v2/invoices/{id}/notify — re-fires the webhook for the invoice on demand (useful for recovery or local-dev testing).
  • GET /api/v2/notifications — paginated audit log of every delivery attempt (successful, retrying, or given up).