---
title: "Verify MyFatoorah Webhook Signatures — Free Online Tool | WebhookRelay"
meta:
  "og:description": "Free online MyFatoorah webhook signature verifier. Validate the MyFatoorah-Signature header against the canonical Key=Value string. Paste the payload, secret and signature to check it instantly — runs in your browser, no signup."
  "og:title": "Verify MyFatoorah Webhook Signatures — Free Online Tool"
  description: "Free online MyFatoorah webhook signature verifier. Validate the MyFatoorah-Signature header against the canonical Key=Value string. Paste the payload, secret and signature to check it instantly — runs in your browser, no signup."
---

# **Verify MyFatoorah Webhook Signatures**

MyFatoorah v2 webhooks don't sign the raw body — they build a canonical `Key=Value,…` string from specific `Data` fields in a fixed per-event order, HMAC-SHA256 it with your webhook secret key, and send the **base64** result in the `MyFatoorah-Signature` header. Construct that string (see the steps below), then paste it with your secret and the header value.

**Signed string (ordered Key=Value pairs)**

MyFatoorah v2 signs a comma-joined `Key=Value` string built from specific `Data` fields in a fixed order per event — **not** the raw body. Build that string (see below) and paste it here.

**Webhook secret key**

**Computed signature**

**Signature to verify **(MyFatoorah-Signature)

**Paste the MyFatoorah-Signature value above to compare**

Everything runs in your browser — the payload and secret never leave this page. Want to verify a different provider? See the [webhook signature verifier hub](https://webhookrelay.com/verify-myfatoorah-webhook-signature/verify-webhook-signature/) or the generic [HMAC generator](https://webhookrelay.com/verify-myfatoorah-webhook-signature/hmac-verification/).

## **How MyFatoorah signs webhooks**

1. Take the fields from the webhook's `Data` object in the **exact order documented for that event**. For a payment status change: `Invoice.Id`, `Invoice.Status`, `Transaction.Status`, `Transaction.PaymentId`, `Invoice.ExternalIdentifier`.
2. Join them as `Key=Value` pairs separated by commas, replacing any null value with an empty string. This is the signed string (the order is fixed per event — it is not alphabetical).
3. Compute HMAC-SHA256 of that string using your webhook secret key (UTF-8) as the key.
4. Base64-encode the digest and constant-time compare it to the `MyFatoorah-Signature` header.

**References & official docs:**

- [MyFatoorah — Webhook signature](https://docs.myfatoorah.com/docs/webhook-signature)
- [MyFatoorah — Webhook v2 overview](https://docs.myfatoorah.com/docs/webhook-v2)
- [MyFatoorah — Payment status data model (field order)](https://docs.myfatoorah.com/docs/webhook-v2-payment-status-data-model)

## **Verify MyFatoorah signatures in code**

**Node.js**

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

// Fixed field order per MyFatoorah v2 event (dot-paths into payload.Data).
const FIELDS = {
  PAYMENT_STATUS_CHANGED: ['Invoice.Id','Invoice.Status','Transaction.Status','Transaction.PaymentId','Invoice.ExternalIdentifier'],
  REFUND_STATUS_CHANGED:  ['Refund.Id','Refund.Status','Amount.ValueInBaseCurrency','ReferencedInvoice.Id'],
};

const get = (o, path) => {
  const v = path.split('.').reduce((x, k) => (x == null ? undefined : x[k]), o);
  return v == null ? '' : String(v);          // null -> empty string
};

const event = JSON.parse(rawBody);
const signed = FIELDS[event.Event.Name]
  .map(f => \`${f}=${get(event.Data, f)}\`).join(',');

const expected = crypto
  .createHmac('sha256', process.env.MYFATOORAH_WEBHOOK_SECRET)
  .update(signed).digest('base64');

const valid = crypto.timingSafeEqual(
  Buffer.from(expected), Buffer.from(req.headers['myfatoorah-signature']));
```

**Python**

```
import hmac, hashlib, base64, json

FIELDS = {
    "PAYMENT_STATUS_CHANGED": ["Invoice.Id","Invoice.Status","Transaction.Status","Transaction.PaymentId","Invoice.ExternalIdentifier"],
    "REFUND_STATUS_CHANGED":  ["Refund.Id","Refund.Status","Amount.ValueInBaseCurrency","ReferencedInvoice.Id"],
}

def get(data, path):
    cur = data
    for k in path.split("."):
        cur = cur.get(k) if isinstance(cur, dict) else None
    return "" if cur is None else str(cur)      # null -> empty string

event = json.loads(raw_body)
signed = ",".join(f"{f}={get(event['Data'], f)}"
                  for f in FIELDS[event["Event"]["Name"]])

expected = base64.b64encode(hmac.new(
    secret.encode(), signed.encode(), hashlib.sha256).digest()).decode()

valid = hmac.compare_digest(expected, request.headers["MyFatoorah-Signature"])
```

## **Frequently asked questions**

<details>

<summary>**What does MyFatoorah actually sign?**</summary>



Not the raw JSON body. It signs a comma-separated `Key=Value` string built from a fixed set of `Data` fields, in the exact order documented for that event type, with any null value replaced by an empty string.

</details>

<details>

<summary>**Which fields go into the signed string?**</summary>



It depends on the event. For `PAYMENT_STATUS_CHANGED` it is `Invoice.Id`, `Invoice.Status`, `Transaction.Status`, `Transaction.PaymentId`, `Invoice.ExternalIdentifier`. Each event's data-model page lists its own order — follow it exactly, it is not alphabetical.

</details>

<details>

<summary>**Where is the webhook secret key?**</summary>



In the MyFatoorah portal under Integration Settings → Webhook Settings, where you also choose v1 or v2. v2 requires the secret key. It is used as a raw UTF-8 string, not decoded.

</details>

## **Verify other providers**

[![Stripe logo](https://webhookrelay.com/verify-myfatoorah-webhook-signature/images/landing/logos/stripe.svg)Stripe](https://webhookrelay.com/verify-myfatoorah-webhook-signature/verify-stripe-webhook-signature/) [![GitHub logo](https://webhookrelay.com/verify-myfatoorah-webhook-signature/images/landing/logos/github.svg) GitHub](https://webhookrelay.com/verify-myfatoorah-webhook-signature/verify-github-webhook-signature/) [![Shopify logo](https://webhookrelay.com/verify-myfatoorah-webhook-signature/images/landing/logos/shopify.svg) Shopify](https://webhookrelay.com/verify-myfatoorah-webhook-signature/verify-shopify-webhook-signature/) [![Slack logo](https://webhookrelay.com/verify-myfatoorah-webhook-signature/images/landing/logos/slack.svg) Slack](https://webhookrelay.com/verify-myfatoorah-webhook-signature/verify-slack-webhook-signature/) [![Twilio logo](https://webhookrelay.com/verify-myfatoorah-webhook-signature/images/landing/logos/twilio.svg) Twilio](https://webhookrelay.com/verify-myfatoorah-webhook-signature/verify-twilio-webhook-signature/) [**S** Standard Webhooks](https://webhookrelay.com/verify-myfatoorah-webhook-signature/verify-standard-webhooks-signature/) [![Square logo](https://webhookrelay.com/verify-myfatoorah-webhook-signature/images/landing/logos/square.svg) Square](https://webhookrelay.com/verify-myfatoorah-webhook-signature/verify-square-webhook-signature/) [**L** LINE](https://webhookrelay.com/verify-myfatoorah-webhook-signature/verify-line-webhook-signature/) [**A** Airwallex](https://webhookrelay.com/verify-myfatoorah-webhook-signature/verify-airwallex-webhook-signature/) [![Zendesk logo](https://webhookrelay.com/verify-myfatoorah-webhook-signature/images/landing/logos/zendesk.svg) Zendesk](https://webhookrelay.com/verify-myfatoorah-webhook-signature/verify-zendesk-webhook-signature/) [![DocuSign logo](https://webhookrelay.com/verify-myfatoorah-webhook-signature/images/landing/logos/docusign.svg) DocuSign](https://webhookrelay.com/verify-myfatoorah-webhook-signature/verify-docusign-webhook-signature/) [**K** Klarna](https://webhookrelay.com/verify-myfatoorah-webhook-signature/verify-klarna-webhook-signature/) [**A** Attio](https://webhookrelay.com/verify-myfatoorah-webhook-signature/verify-attio-webhook-signature/)

[HMAC Generator](https://webhookrelay.com/verify-myfatoorah-webhook-signature/hmac-verification/) [CloudEvents Validator](https://webhookrelay.com/verify-myfatoorah-webhook-signature/cloudevents-validator/) [Webhook Tester (Bin)](https://webhookrelay.com/verify-myfatoorah-webhook-signature/webhook-bin/)

Receiving MyFatoorah webhooks on a server behind a firewall or on localhost? Webhook Relay can [forward them to your internal service](https://webhookrelay.com/verify-myfatoorah-webhook-signature/webhooks/) and even [verify or transform them](https://webhookrelay.com/verify-myfatoorah-webhook-signature/features/transform-webhooks/) before delivery.