# Payrix Pro Webhooks

Payrix Pro (Worldpay's payment facilitation platform; not Payrix Payments) sends a webhook when
an alert fires. Each alert has actions with an Endpoint and an optional header name and header
value. Requests are **not signed**: there is no HMAC and no timestamp. You authenticate a request
by checking the secret header you put on the action.

> Set a Header Name and Header Value on each Payrix Pro webhook action. Actions without one send nothing to verify.

## When to Use This Skill

* How do I receive Payrix Pro webhooks?
* Does Payrix Pro sign webhook payloads? (No: use a secret header on the action)
* How do I authenticate a Payrix Pro webhook with a Header Name and Header Value?
* Why does my Payrix Pro webhook endpoint return 401?
* Which HTTP method and content type does Payrix Pro use?

## Verification (core)

```javascript
const crypto = require('crypto');

// Hash both sides: equal-length buffers, so timingSafeEqual never throws.
function safeEqual(a, b) {
  const ha = crypto.createHash('sha256').update(String(a), 'utf8').digest();
  const hb = crypto.createHash('sha256').update(String(b), 'utf8').digest();
  return crypto.timingSafeEqual(ha, hb);
}

function verifyPayrixProRequest(
  headers,
  secret = process.env.PAYRIX_PRO_WEBHOOK_SECRET,
  headerName = process.env.PAYRIX_PRO_WEBHOOK_HEADER || 'Authorization'
) {
  if (!secret) return false;                       // never accept when unconfigured
  const received = headers[headerName.toLowerCase()];
  return typeof received === 'string' && received !== '' && safeEqual(received, secret);
}

```

* The header name is whatever you typed on the action, so it is read from
  `PAYRIX_PRO_WEBHOOK_HEADER` (default `Authorization`) and looked up case-insensitively.
* `PAYRIX_PRO_WEBHOOK_SECRET` is the **exact, whole header value**, including any `Bearer `
  prefix you typed. Compare the whole value; do not strip or parse a prefix.
* Python: `hmac.compare_digest` on bytes (`.encode()` both sides; passing `str` raises on non-ASCII).
* Return `401` for a missing header or mismatch, for **every** HTTP method, before reading the body.
* **Security limit:** a static shared credential authenticates the sender, not the body, and gives
  no replay protection (no signature, no timestamp). Use HTTPS and rotate the credential if it leaks.

> **For complete handlers with tests**, see [examples/express/](https://github.com/hookdeck/webhook-skills/tree/main/skills/payrix-pro-webhooks/examples/express/), [examples/nextjs/](https://github.com/hookdeck/webhook-skills/tree/main/skills/payrix-pro-webhooks/examples/nextjs/), [examples/fastapi/](https://github.com/hookdeck/webhook-skills/tree/main/skills/payrix-pro-webhooks/examples/fastapi/).

## Methods and Body

Payrix's docs don't name the HTTP method, and each action has its own format (Content-Type)
setting. The examples therefore accept GET, POST, PUT, PATCH and DELETE, check the credential
first, and handle an empty body. Hookdeck's Payrix Pro source pre-selects POST without managing
the method, so any other method the sender uses must also be allowed on the source.

The body isn't documented either. The examples parse JSON when the content type says so and
otherwise keep the raw text. Express reads the raw body with `express.raw({ type: '*/*' })` and
parses only after the credential check.

## Alerts

No event names are documented; the payload shape depends on the alert and the action's format
setting. The examples use clearly labelled illustrative payloads, for example a transaction alert:

```json
{ "alert": "transaction", "transaction": { "id": "t1_txn_example", "total": 1500 } }

```

Dispatch on the fields your own alerts actually send.

## Environment Variables

```bash
PAYRIX_PRO_WEBHOOK_HEADER=Authorization    # Header Name set on the webhook action
PAYRIX_PRO_WEBHOOK_SECRET=your-secret      # exact, whole Header Value (e.g. "Bearer abc123")

```

## Local Development

Payrix can't reach `localhost`. Tunnel with the Hookdeck CLI (no account required):

```bash
npx hookdeck-cli listen 3000 payrix-pro --path /webhooks/payrix-pro

```

Use the printed URL as the Endpoint on the webhook action.

## Resources

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/payrix-pro-webhooks/references/overview.md) - What Payrix Pro webhooks are, alerts and payload shape
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/payrix-pro-webhooks/references/setup.md) - Configure the action's Endpoint, Header Name and Header Value
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/payrix-pro-webhooks/references/verification.md) - Header check details, gotchas, debugging 401s
* [examples/](https://github.com/hookdeck/webhook-skills/tree/main/skills/payrix-pro-webhooks/examples/) - Runnable Express, Next.js and FastAPI handlers with tests