Stripe sends events to POST /wp-json/formforge/v1/stripe/webhook.
Signature Verification
php
$payload = file_get_contents( 'php://input' );
$sig_header = $_SERVER['HTTP_STRIPE_SIGNATURE'] ?? '';
// Parse: t=1705762522,v1=abc123def456...
$parts = [];
foreach ( explode( ',', $sig_header ) as $item ) {
list( $key, $value ) = explode( '=', $item, 2 );
$parts[ $key ] = $value;
}
// Reject events older than 5 minutes
if ( abs( time() - (int) $parts['t'] ) > 300 ) {
return new WP_REST_Response( [ 'error' => 'Timestamp too old' ], 400 );
}
// HMAC verification
$signed_payload = $parts['t'] . '.' . $payload;
$expected = hash_hmac( 'sha256', $signed_payload, $webhook_secret );
if ( ! hash_equals( $expected, $parts['v1'] ) ) {
return new WP_REST_Response( [ 'error' => 'Signature mismatch' ], 400 );
}Handled Events
| Event | Action |
|---|---|
payment_intent.succeeded | Marks payment_status as succeeded and adds _payment data, for a payment made for the same form. A submission that holds the payment in one of its payment fields goes through the same checks as at submit (this form and field, the currency, the amount kept with the submission, one payment for one submission), and a row that is paid, refunded or kept for another amount is not raised by the event |
payment_intent.payment_failed | Marks payment_status as failed |
charge.refunded | Reads data.object.payment_intent and marks payment_status as refunded |
Webhook Setup in Stripe Dashboard
- Go to Stripe Dashboard > Developers > Webhooks
- Click “Add endpoint”
- Enter URL:
https://example.com/wp-json/formforge/v1/stripe/webhook - Select events:
payment_intent.succeeded,payment_intent.payment_failed,charge.refunded - Copy the signing secret (
whsec_...) to Fillin Forge settings
—