Agent skill

PayPro Global Webhooks (IPN) Skill

Receive and verify PayPro Global IPN (Instant Payment Notification) webhooks. Use when setting up a PayPro Global IPN handler, debugging the SIGNATURE (SHA256) or HASH (MD5) verification, or handling order and subscription events like OrderCharged, OrderRefunded, and SubscriptionChargeSucceed. Payloads are form-encoded (application/x-www-form-urlencoded), not JSON.

Install this skill

npx skills add hookdeck/webhook-skills --skill paypro-global-webhooks


PayPro Global calls its webhooks IPNInstant Payment Notification. When an order or subscription event occurs, PayPro Global sends an HTTP POST with a application/x-www-form-urlencoded body (not JSON) to the IPN URL you configure. Verification is bespoke: it is not HMAC-in-a-header and not Standard Webhooks.

When to Use This Skill

  • How do I receive PayPro Global IPN webhooks?
  • How do I verify the PayPro Global SIGNATURE (SHA256) parameter?
  • How do I verify the PayPro Global HASH (MD5) parameter?
  • Why is my PayPro Global signature verification failing?
  • How do I handle OrderCharged, OrderRefunded, or SubscriptionChargeSucceed events?
  • How do I restrict IPN requests to PayPro Global's IP addresses?

Verification (core)

PayPro Global has three independent layers — verify all that you can:

  1. IP allowlist — requests come only from fixed PayPro Global IPs (IPv4 198.199.123.239, 157.230.8.40; IPv6 2604:a880:400:d0::1843:7001, 2604:a880:400:d1::b6c:c001).
  2. SIGNATURESHA256 (hex) over seven field values concatenated in this exact order: ORDER_ID + ORDER_STATUS + ORDER_TOTAL_AMOUNT + CUSTOMER_EMAIL + VALIDATION_KEY + TEST_MODE + IPN_TYPE_NAME.
  3. HASHMD5 of ORDER_ID + SecretKey for real orders, or MD5("1") for test orders.

VALIDATION_KEY (for SIGNATURE) and SecretKey (for HASH) are two different keys. Both live under Store Settings → General Settings → Integration. Mixing them up is the most common verification bug.

The signature covers specific field values, not the raw request body — so parsing the form first is correct here (unlike HMAC-over-raw-body providers). Recompute server-side and compare timing-safely (Node):

const crypto = require('crypto');

// SIGNATURE = SHA256(ORDER_ID + ORDER_STATUS + ORDER_TOTAL_AMOUNT +
//   CUSTOMER_EMAIL + VALIDATION_KEY + TEST_MODE + IPN_TYPE_NAME). Order and the
// inclusion of TEST_MODE + IPN_TYPE_NAME are easy to get wrong — keep them exact.
function verifySignature(f, validationKey) {
  const base = `${f.ORDER_ID ?? ''}${f.ORDER_STATUS ?? ''}${f.ORDER_TOTAL_AMOUNT ?? ''}` +
    `${f.CUSTOMER_EMAIL ?? ''}${validationKey}${f.TEST_MODE ?? ''}${f.IPN_TYPE_NAME ?? ''}`;
  const expected = crypto.createHash('sha256').update(base, 'utf8').digest('hex');
  const a = Buffer.from(expected);
  const b = Buffer.from(String(f.SIGNATURE ?? '').toLowerCase());
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

For complete handlers with HASH verification, IP allowlisting, event dispatch, and tests, see:

Common Event Types

The event name arrives in the IPN_TYPE_NAME field. Note the non-standard spelling SubscriptionChargeSucceed (not "Succeeded").

IPN_TYPE_NAMETriggered WhenCommon Use Cases
OrderChargedA one-time order (or first subscription charge) is paidFulfil order, grant access, send license
OrderRefundedAn order is fully refundedRevoke access, update accounting
OrderPartiallyRefundedAn order is partially refundedAdjust balance, partial revoke
OrderChargedBackA chargeback is openedSuspend account, gather evidence
OrderChargedBackWonA chargeback dispute is wonRestore access
OrderDeclinedA payment attempt is declinedNotify customer, retry flow
SubscriptionChargeSucceedA recurring subscription charge succeedsExtend subscription period
SubscriptionChargeFailedA recurring charge failsDunning, notify customer
SubscriptionRenewedA subscription renewsExtend access
SubscriptionSuspendedA subscription is suspendedPause access
SubscriptionTerminatedA subscription is terminatedRevoke access
SubscriptionFinishedA subscription reaches its natural endOffer renewal

See references/overview.md for the full event list.

Environment Variables

PAYPRO_VALIDATION_KEY=your_validation_key   # For SIGNATURE (SHA256). Store Settings → General Settings → Integration
PAYPRO_SECRET_KEY=your_secret_key           # For HASH (MD5). Same tab, DIFFERENT key. Optional but recommended.

Local Development

# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 paypro-global --path /webhooks/paypro-global

Reference Materials


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Aug 5, 2026

View on GitHub →