Webhooks
What it is
The single entry point for external providers to notify the platform of events — payment confirmations (Paystack), wallet/transfer events (PiggyVest Business), and delivery/fulfillment updates (GetIT, for physical gift orders — see Gift & Giftstore). Every "the webhook confirms it, not the client" pattern referenced throughout Payments and PartyBank terminates here.
Core concepts
- One route per provider, all under
/v1/webhooks/*:POST /paystack,POST /piggyvest-business,POST /getit. Each has a matchingGET(used for provider dashboard "verify this URL is reachable" checks, not for receiving real events). - Signature verification is provider-specific and not uniformly enforced today. Paystack's webhook actively verifies an HMAC-SHA512 signature (
x-paystack-signatureagainst the secret key) and rejects the request if it doesn't match. The PiggyVest Business webhook's equivalent signature check exists in the code but is commented out — the endpoint currently processes payloads without verifying they actually came from PiggyVest. If you're touching this module, that's worth treating as a real gap rather than assuming parity with the Paystack path.
How it works
- Paystack (
paystack-webhook.service.ts): verifies the HMAC signature first; only on success does it proceed to match the payload against a payment tracking record and call intoPaymentsService(recordPayout, tracking updates — see Payments & Payouts). - PiggyVest Business (
webhook.service.ts): a single endpoint handles multiple PVB event types (wallet funding, transfer completion, etc.) viaprocessPiggyvestBusinessWebhook, routed internally byeventType. This is what confirms PartyBank/personal-wallet bank transfers and thepiggy.payment.successevent referenced in the PartyBank guide. - GetIT (
getit-webhook.service.ts): delivery validation and fulfillment completion callbacks for physical gift-box orders — a different domain (logistics) from the other two (payments).
Key business rules & edge cases
- Don't assume the PVB webhook payload is authenticated as currently implemented — if you're relying on data from it for anything security-sensitive, treat this as an open item rather than a settled guarantee. Re-enabling the commented-out
verifySignaturecheck (mirroring the Paystack implementation) is the fix if/when this gets picked up. - All three webhooks are public, unauthenticated routes by necessity (external providers can't hold a platform JWT) — the only thing standing between "real event" and "forged event" is signature verification, which is why the PVB gap above matters more than it might on a route with other layers of defense.
- The
tests/test-processingendpoints exist for local development against webhook logic without needing a real provider callback —test-processingrequires a local key,testsdoesn't appear to, so don't expose either publicly in a way that lets someone inject fake webhook processing.
Related endpoints
POST /v1/webhooks/paystack, POST /v1/webhooks/piggyvest-business, POST /v1/webhooks/getit. Not applicable to the generated OpenAPI spec in the usual sense (these are provider-facing, not client-facing).
Related code
src/modules/webhooks/webhook.routes.ts,webhooks.controller.tssrc/modules/webhooks/paystack-webhook.service.ts— active signature verificationsrc/modules/webhooks/webhook.service.ts— PiggyVest Business (verifySignaturepresent but not called)src/modules/webhooks/getit-webhook.service.ts