PayPal payment notifications on your phone
PayPal's own app tells you money arrived – eventually, and with the same sound as everything else. If you want a payment to be unmistakable, or you want your own system to react the moment it lands, PayPal's webhooks are the way, and you don't need a server to use them.
Three ways to be notified about a PayPal payment
They solve different problems, so it's worth being clear about which one you actually need:
- The PayPal app. Turn on notifications in the app and you'll get a push for incoming money. Free, zero setup, but you can't change the sound, you can't filter to only the events you care about, and it's one more app competing for your attention.
- A PayPal webhook straight to your phone. PayPal POSTs to a URL you choose. Point that URL at a Webhooky endpoint and you get a notification with your own sound – no server, no code.
- A PayPal webhook into your own backend. The real integration: verify the signature, update your database, then notify. Necessary if the payment has to do something, not just be announced.
How PayPal webhooks work
PayPal sends an HTTPS POST to a listener URL whenever a subscribed event happens. The listener belongs to a specific REST app in the Developer Dashboard – only that app's events reach it – and you can register up to 10 URLs per app, subscribing to individual event types or to all of them with *.
The events you'll want for incoming money:
PAYMENT.CAPTURE.COMPLETED– a payment capture completed. This is the one that means "the money is yours".CHECKOUT.ORDER.APPROVED– the buyer approved the order, before capture.PAYMENT.CAPTURE.DECLINED– a capture was declined.PAYMENT.CAPTURE.REFUNDED– you refunded a capture.PAYMENT.CAPTURE.REVERSED– PayPal reversed a capture. Worth its own loud sound.CUSTOMER.DISPUTE.CREATED– a dispute was opened. Also worth its own sound.PAYMENT.SALE.COMPLETED– the recurring-payment equivalent for subscriptions.
A note on the older integration: PayPal's IPN (Instant Payment Notification) still exists and PayPal's NVP/SOAP documentation describes it as a legacy integration method – PayPal still supports existing ones but recommends newer solutions for new work. Various third-party guides circulate specific IPN shutdown dates; PayPal's own documentation doesn't state one, so we won't repeat them. If you're starting now, use REST webhooks.
The no-server route: PayPal → your phone
A Webhooky endpoint is a URL that accepts any HTTP POST and turns it into a push notification. PayPal needs a publicly reachable HTTPS listener URL. That's the whole integration:
- In the Webhooky app, create an endpoint. Call it PayPal, set the message to something like “Payment received”, pick the
cash_registerorka_chingsound and copy the URL. - In the PayPal Developer Dashboard, open your REST app and add a webhook listener with that URL.
- Subscribe to
PAYMENT.CAPTURE.COMPLETED. Save.
PayPal's payload is a large JSON object describing the event. Webhooky doesn't need to understand it: because the body has no title or message field, it falls back to the title, text and sound you configured on the endpoint. You get an instant, distinctly-sounding "payment received" on every device you're signed in on.
Two honest caveats. Webhooky does not verify PayPal's signature, so anyone who learns your endpoint URL could trigger a notification – for an alert that's a nuisance, not a breach, but it's why this route is for being told, not for bookkeeping. And the notification won't contain the amount, because that would require parsing PayPal's payload. If you want "€49.00 from Anna", take the backend route below.
One thing that works in your favour here: PayPal retries hard. A non-2xx response is retried up to 25 times over three days before the delivery is marked Failed. Webhooky always answers 200, including when you've hit the free tier's limit, so you never accumulate a backlog of failed deliveries.
The backend route: amount, currency and buyer
To say what actually arrived, receive the webhook yourself, verify it, then forward a formatted message:
export async function onPayPalWebhook(req, res) {
res.sendStatus(200); // ack first - PayPal retries for 3 days
const event = req.body;
if (event.event_type !== "PAYMENT.CAPTURE.COMPLETED") return;
const amount = event.resource?.amount;
const payer = event.resource?.payer?.name?.given_name ?? "someone";
await fetch(process.env.WEBHOOKY_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
title: "💰 PayPal payment",
message: `${amount.value} ${amount.currency_code} from ${payer}`,
sound: "cash_register",
}),
});
}
Acknowledge before you do the work. PayPal's retry window is generous but your endpoint still has a timeout, and a slow handler turns one payment into several delivery attempts.
Verifying that it really came from PayPal
PayPal offers two ways. You can compute the CRC32 of the message and verify its signature yourself, or you can send the message, your stored webhook ID and the request's header information to PayPal's verify-signature endpoint and let PayPal do the check. The second is slower but much harder to get wrong. Without verification you cannot know that a POST to your listener actually came from PayPal.
Give each event its own sound
This is where a dedicated endpoint beats the PayPal app. Create one endpoint per event type and assign sounds that mean something: a cash register for PAYMENT.CAPTURE.COMPLETED, a buzzer for PAYMENT.CAPTURE.DECLINED, something unmistakably unpleasant for CUSTOMER.DISPUTE.CREATED. After a week you'll know what happened without taking the phone out of your pocket. There are 40 sounds to pick from, and each endpoint keeps its own history.
No PayPal developer account? Use Zapier or Make
The Developer Dashboard assumes a REST app, which is more than some sellers want to set up. Zapier, Make and IFTTT all have PayPal triggers that handle the connection for you – build the trigger, add a Webhooks → POST action pointing at your Webhooky URL, and map the amount into the message. The trade-off is latency: these poll on a schedule, so expect minutes rather than seconds.
Frequently asked questions
How do I get a notification when I receive a PayPal payment?
Either turn on notifications in the PayPal app, or subscribe a webhook to PAYMENT.CAPTURE.COMPLETED in the PayPal Developer Dashboard and point it at a URL that notifies you. Pointing it at a Webhooky endpoint gives you a push with your own sound and needs no server.
What is the PayPal webhook event for a completed payment?
PAYMENT.CAPTURE.COMPLETED for one-off payments, and PAYMENT.SALE.COMPLETED for recurring subscription payments.
Is PayPal IPN still supported?
IPN still exists, and PayPal's documentation describes NVP/SOAP as a legacy integration method that it continues to support while recommending newer solutions for new integrations. For anything you're building now, REST webhooks are the right choice.
How often does PayPal retry a failed webhook?
Your listener must return a 2xx status. Anything else is retried up to 25 times over three days, after which the delivery is marked Failed. You can resend it manually from the Webhook Events dashboard.