Developer hooks & webhooks

Hook into donations in PHP, or receive a signed webhook anywhere.

Action: a donation completed

Fires once when a donation is confirmed paid (one-time, recurring first payment, or a renewal).

add_action( 'donor_merchant_donation_completed', function ( $donation ) {
    // $donation->amount, ->total, ->currency, ->frequency,
    // ->campaign_id, ->designation, ->donor_id, ->meta (JSON), ...
} );

Action: an offline gift was pledged

Fires when a donor chooses to give by check or bank transfer. The gift is saved as awaiting payment; donor_merchant_donation_completed fires later, when you click Mark received.

add_action( 'donor_merchant_offline_pledged', function ( $donation ) {
    // $donation->status is 'awaiting'.
} );

Filters

FilterWhat it changes
donor_merchant_receipt_emailThe donor receipt before sending - ( array $email, $donation, $donor ) with subject, body, headers.
donor_merchant_monthly_report_emailThe monthly summary email - ( array $email, array $stats ).
donor_merchant_estimated_feeThe fee charged when a donor covers fees - ( float $fee, float $amount, string $method ), where $method is card or us_bank_account. The form's label comes from the fee settings, so change those if you want the shown figure to move.
donor_merchant_rate_limitMax donation attempts per IP per hour - ( int $limit ).
donor_merchant_offline_rate_limit / donor_merchant_offline_email_limitMax offline pledges per IP (default 5) and per email address (default 3) per hour - ( int $limit ).
donor_merchant_suppress_receiptReturn true to skip a donor receipt - ( bool, $donation ).
donor_merchant_suppress_admin_notificationReturn true to skip the admin notice - ( bool, $donation ).
donor_merchant_emailAny plugin email just before it sends - ( array $email, string $id, array $context ). $id is receipt, renewal, offline, admin_new, portal or monthly.
donor_merchant_pre_donationReturn a WP_Error to reject a donation before anything is saved or charged - ( null, WP_REST_Request $request ). The supported way to add a CAPTCHA.
donor_merchant_client_ipThe visitor IP used for rate limiting, for sites behind a proxy or CDN - ( string $ip ).
donor_merchant_min_fill_secondsFastest allowed form submission in seconds (default 3, 0 turns it off) - ( int $seconds ).
donor_merchant_stale_donation_daysDays before unfinished donation attempts are cleared (default 90, 0 turns it off) - ( int $days ).
// Example: tweak the receipt subject.
add_filter( 'donor_merchant_receipt_email', function ( $email, $donation, $donor ) {
    $email['subject'] = 'We received your gift, ' . $donor->first_name . '!';
    return $email;
}, 10, 3 );

Outgoing webhooks

Add one or more URLs under Settings → Integrations and Donor Merchant POSTs a JSON payload to each on every completed donation - perfect for Zapier, Make, or your own endpoint.

{
  "event": "donation.completed",
  "donation": {
    "id": 123, "amount": 50, "fee_amount": 0, "total": 50,
    "currency": "USD", "frequency": "monthly", "status": "completed",
    "payment_method": "stripe", "transaction_id": "pi_...",
    "campaign": "Spring Appeal", "designation": "Scholarship Fund",
    "tribute_type": "", "tribute_name": "", "employer_match": "",
    "created_at": "2026-06-14 10:00:00",
    "custom_fields": [ { "label": "How did you hear?", "value": "Friend" } ]
  },
  "donor": { "first_name": "Sam", "last_name": "Rivera", "email": "sam@example.org", "phone": "" },
  "organization": "Hope Community Center",
  "site": "https://example.org"
}

Verifying the signature

Each request includes an X-Donor-Merchant-Signature header - an HMAC-SHA256 of the raw body using your outgoing webhook secret. Verify it like so:

$payload   = file_get_contents( 'php://input' );
$signature = $_SERVER['HTTP_X_DONOR_MERCHANT_SIGNATURE'] ?? '';
$expected  = hash_hmac( 'sha256', $payload, $your_secret );
if ( hash_equals( $expected, $signature ) ) {
    // Trusted.
}

Shortcodes & REST

Render anywhere with [donor_merchant], [donor_merchant campaign="N"], [donor_merchant_progress campaign="N"], and [donor_merchant_portal]. The donation, verification, and webhook endpoints live under the REST namespace donor-merchant/v1.

It's all GPLNothing here is gated. The whole plugin is open source - read it, fork it, build on it.

Get Donor Merchant

Free from WordPress.org. Card numbers never touch your site.

Download Donor Merchant free Or try the demo first.