Welcome to the Jose Madrid Salsa developer docs — explore features, APIs, and deployment guides.
Jose Madrid SalsaJMS Docs

Webhooks

The five inbound webhook endpoints, how each verifies its sender, and what it changes.

Webhooks

Five providers post events to the storefront. Webhooks are what finalise an order — the browser returning from a payment page is a hint, not a fact. Every endpoint lives under app/api/webhooks/.

EndpointProviderVerified with
/api/webhooks/stripeStripestripe-signature header, STRIPE_WEBHOOK_SECRET
/api/webhooks/paypalPayPalPayPal's verify-webhook-signature API, PAYPAL_WEBHOOK_ID
/api/webhooks/squareSquareSquare adapter signature check
/api/webhooks/easypostEasyPostEASYPOST_WEBHOOK_SECRET
/api/webhooks/resendResendResend SDK / Svix headers, RESEND_WEBHOOK_SECRET

Every endpoint rejects an unverified request. A missing secret is a failure, not a bypass — if PAYPAL_WEBHOOK_ID is unset the route logs CRITICAL and refuses.

Stripe

Handled events:

EventEffect
payment_intent.succeededMark Payment SUCCEEDED, Order PROCESSING, decrement inventory
payment_intent.payment_failedMark the payment failed
payment_intent.canceledCancel the payment, release held inventory
charge.refundedRecord a Refund
checkout.session.completedFinalise a Checkout Session order
invoice.payment_succeededInvoice settlement

Anything else is logged as unhandled and acknowledged — returning an error for an event you do not care about makes Stripe retry it forever.

PayPal

EventEffect
PAYMENT.CAPTURE.COMPLETEDMark paid, move the order to PROCESSING
PAYMENT.CAPTURE.REFUNDEDRecord a refund

Verification is a round-trip to PayPal's own API rather than a local HMAC, so the handler is only as fast as that call.

Square

EventEffect
payment.completedMark paid — covers both online and POS takings
refund.created, refund.updatedRecord or update a refund

EasyPost

Switches on event.description:

EventEffect
tracker.created, tracker.updatedUpdate shipment tracking status

Resend

EventEffect
email.bouncedWrite EmailBounce, add to EmailSuppression
email.complainedSuppress the address
email.deliveredLog delivery
email.openedRecord an open
email.clickedRecord a click

Suppressions are honoured by the campaign sender — see Email Marketing.

Idempotency

WebhookEvent records each event by providerEventId (and stripeEventId for Stripe), with a processed flag. Providers retry, and the same event will arrive more than once; the record is what makes a replay a no-op rather than a second inventory decrement.

Testing locally

stripe listen --forward-to localhost:3000/api/webhooks/stripe

The other providers need a public tunnel. Point the provider's dashboard at the tunnel URL and use its own secret — a webhook signed for production will not verify against a development secret, which is the intended behaviour.

How is this guide?

Edit on GitHub

Last updated on

On this page