# Verifying Webhook Signatures — Stripe Payments

Source: https://www.skillbyai.com/en/stripe-payments/w-verify

> The raw body and the endpoint secret.

## Signatures prove the event came from Stripe

Anyone can POST to a public URL, so every webhook must be **verified**. Stripe signs each request and puts the signature and a timestamp in the `Stripe-Signature` header. Your endpoint has a **signing secret** (`whsec_...`). The library's `stripe.webhooks.constructEvent(rawBody, signature, secret)` recomputes the signature and throws if it does not match or the timestamp is too old, which also guards against replayed requests. The check needs the **exact raw request body**: if a JSON body parser has already parsed and re-serialised it, verification fails.

## An Express webhook endpoint

Use the raw body for this route only.

```javascript
import express from 'express';
const app = express();

app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
  const signature = req.headers['stripe-signature'];
  let event;
  try {
    event = stripe.webhooks.constructEvent(req.body, signature, process.env.STRIPE_WEBHOOK_SECRET);
  } catch (err) {
    return res.status(400).send(`Webhook signature verification failed: ${err.message}`);
  }
  await handleEvent(event);      // keep this quick, or enqueue it
  res.json({ received: true });  // a 2xx tells Stripe the delivery succeeded
});

// register JSON parsing for other routes after the webhook route
app.use(express.json());

```

## Each endpoint has its own secret

The secret printed by the Stripe CLI, the test-mode endpoint secret and the live-mode endpoint secret are all different. A signature error after deploying usually means the wrong secret or a parsed body.

**Quiz:** What does constructEvent need in order to verify a webhook?

- [ ] Only the event ID
- [ ] The parsed JSON body and the publishable key
- [x] The raw request body, the Stripe-Signature header and the endpoint secret
- [ ] The secret API key and the customer ID

*Answer:* The raw request body, the Stripe-Signature header and the endpoint secret. The signature is computed over the exact raw payload.
