← Back to help center

Webhooks

GiveFlow uses incoming webhooks to receive real-time notifications from payment gateways. When a payment event occurs on Stripe or PayPal, the gateway sends a webhook to your site so GiveFlow can update donation records automatically.

How incoming webhooks work

Each gateway has a dedicated webhook endpoint on your site:

POST /giveflow/v1/webhooks/{gateway}

For the two online gateways, those endpoints are:

POST /giveflow/v1/webhooks/stripe
POST /giveflow/v1/webhooks/paypal

When Stripe or PayPal processes a payment, refund, or subscription change, it sends an HTTP POST request to the matching URL. GiveFlow verifies the request signature, identifies the event type, and updates your donation data accordingly.

The Offline and Sandbox gateways take no webhooks. Nothing sent to their endpoints is processed.

Webhook signature verification

Every incoming webhook is verified before GiveFlow acts on it, so a request that did not genuinely come from the gateway, or that was tampered with in transit, changes nothing.

The two gateways verify differently. Stripe deliveries are checked on your own server against the webhook signing secret you saved. PayPal deliveries are checked by calling PayPal back and asking it to verify the transmission headers against the webhook id you saved, so with no webhook id there is nothing to verify against and every delivery is refused.

When verification fails, GiveFlow records the delivery with signature_ok set to false and does nothing else. Stripe deliveries get a 401 and PayPal deliveries get a 400, shown against the delivery in the gateway’s own dashboard.

Stripe webhook events

GiveFlow listens for Stripe webhook events related to payments and subscriptions. When you save your Stripe keys in the GiveFlow gateway settings, GiveFlow registers this endpoint on your Stripe account for you and stores its signing secret. On a local site Stripe cannot reach the endpoint, so nothing is registered: create the webhook yourself in the Stripe dashboard and paste its signing secret into the Stripe card in GiveFlow’s gateway settings.

Common events GiveFlow handles include:

  • Payment completions and failures
  • Subscription renewals and cancellations
  • Refund processing
  • Disputes, both when the funds are withdrawn and when they are reinstated

PayPal webhook events

GiveFlow does not create the PayPal webhook for you. Copy the webhook endpoint from the PayPal card in GiveFlow’s gateway settings, add it as a webhook in your PayPal app, subscribe it to the payment and subscription events, then paste the webhook id back into the same credentials section. Sandbox and live are separate PayPal apps, so each mode has its own webhook and its own id.

Until a webhook id is saved for the mode you are in, PayPal is offered for one-time donations only. It is not offered as an option on a recurring donation at all. PayPal charges the first payment the moment the donor approves a subscription, and the opening sale webhook is the only thing that records that payment, so a recurring donation taken with no webhook id would be charged and never booked.

GiveFlow acts on these events:

  • PAYMENT.CAPTURE.COMPLETED confirms a one-time donation
  • PAYMENT.CAPTURE.DENIED and PAYMENT.CAPTURE.DECLINED mark a one-time donation failed
  • PAYMENT.CAPTURE.REFUNDED records a refund made in the PayPal dashboard against a one-time donation
  • BILLING.SUBSCRIPTION.ACTIVATED marks the recurring plan active
  • BILLING.SUBSCRIPTION.CANCELLED and BILLING.SUBSCRIPTION.EXPIRED end the plan, and email the donor when the end started at PayPal rather than in GiveFlow
  • PAYMENT.SALE.COMPLETED records the opening payment on a new subscription, and every renewal after it

Any other event type is logged and ignored.

Two things Stripe does are not covered on PayPal today. A failed PayPal renewal is not processed: it does not count toward the failure count on the plan, it does not email the donor, and it does not show under the failing filter. Refunds, reversals and disputes are handled for one-time donations only, so a refunded or disputed recurring payment does not update GiveFlow.

Webhook log

GiveFlow records incoming webhook deliveries in the giveflow_webhooks_log database table. A gateway redelivering an event GiveFlow has already logged does not create a second row. Each row records:

  • gateway — which gateway sent the delivery, stripe or paypal
  • event_type — the type of event (for example, payment_intent.succeeded or PAYMENT.CAPTURE.COMPLETED)
  • external_id — the gateway’s identifier for the event, which is also what GiveFlow deduplicates on
  • signature_ok — whether the signature verification passed
  • processed — whether GiveFlow acted on the event, with processed_at for when
  • error — any error message if processing failed
  • payload and headers — the request body and headers exactly as they arrived
  • received_at — when the request arrived

This is a database table with no admin screen. Reading it takes direct database access, so the practical starting points for day-to-day debugging are your gateway’s own delivery log and GiveFlow > Tools > Logs, which shows handler exceptions recorded under a webhook. source.

Log retention

Old webhook log entries are pruned automatically after 30 days. You do not need to clean up the log manually.

Troubleshooting failed webhooks

If donations are not updating after payment, start at the gateway’s own delivery list. In Stripe, that is your dashboard under Developers > Webhooks. In PayPal, open the webhook you added to your REST app at developer.paypal.com.

Signature verification failures

Symptoms: Stripe reports 401 responses, or PayPal reports 400 responses, and donations do not update after payment.

Likely cause: For Stripe, the webhook signing secret is wrong or outdated. For PayPal, the webhook id is missing, or it belongs to a different webhook or a different app.

Solution: For Stripe, verify that the webhook signing secret in the GiveFlow gateway settings matches the one in your Stripe dashboard. For PayPal, verify that the webhook id in the PayPal card is the id of the webhook on the app whose credentials you saved. Test and live are stored separately, so each mode needs its own signing secret or webhook id.

PayPal offers no recurring option

Symptoms: Your form offers recurring donations, but PayPal is missing from the payment options when a donor picks a recurring amount.

Likely cause: No PayPal webhook id is saved for the mode you are in.

Solution: Add the webhook in your PayPal app and paste its id into the PayPal card in the Payment gateways tab. Sandbox and live have separate ids, so saving one does not cover the other. PayPal returns to the recurring options once the id is saved.

Webhooks not arriving

Symptoms: The gateway records no deliveries at all, or every attempt fails to connect.

Likely cause: Your site is not reachable from the internet, or a firewall is blocking incoming POST requests.

Solution:

  1. Confirm your site has a valid SSL certificate and is publicly accessible.
  2. Check that your server or hosting firewall allows POST requests to /giveflow/v1/webhooks/stripe and /giveflow/v1/webhooks/paypal.
  3. Review the webhook delivery logs in your gateway’s dashboard for HTTP errors.

Events not handled

Symptoms: The gateway reports a successful delivery, a 200 response, but nothing changes in GiveFlow.

Likely cause: The event type is not one that GiveFlow processes, or the related donation record was not found. The delivery is still logged, with processed set to false.

Solution: Open the delivery in your gateway’s dashboard and read the response GiveFlow returned. It names the event type GiveFlow saw and whether it was handled. If the event type is one you expect GiveFlow to act on, such as a payment completion, confirm that the donation exists in your GiveFlow records. GiveFlow > Tools > Logs will not help here: it records handler exceptions, and an event GiveFlow simply does not act on is not an exception.

PayPal retries the first subscription payment

Symptoms: PayPal shows a 503 response for a PAYMENT.SALE.COMPLETED delivery, and a later attempt at the same event succeeds.

Likely cause: The sale arrived before the subscription was recorded on your site, so there was nothing to book the payment against yet.

Solution: None needed. GiveFlow answers 503 on purpose so that PayPal redelivers, and the retry records the payment once the plan is on file.