Skip to content

Concept map· 6 connected terms

Webhook mTLS (Mutual TLS)

Also called: Webhook mTLS · Mutual TLS · mTLS · Client certificate authentication

In one line
Requiring Meta's client certificate in the TLS handshake on your webhook endpoint, so only Meta's servers can connect before any payload is read.

Reviewed

What is webhook mTLS?

Webhook mTLS (mutual TLS) is a way of locking a webhook endpoint so that only Meta can connect to it. In ordinary TLS only the server proves its identity; in mutual TLS the server also asks the client for a certificate during the handshake and refuses the connection unless that certificate chains to a trusted certificate authority and names the expected client. For WhatsApp webhooks the client is Meta's webhook infrastructure and the server is your endpoint.

Meta presents a client certificate with the common name client.webhooks.fbclientcerts.com, together with its signing intermediate. That certificate is now signed by a Meta-owned certificate authority: Meta publishes the CA file meta-outbound-api-ca-2025-12.pem for your trust store, replacing the previous DigiCert-signed certificate, which expired on 15 April 2026. Your server, or the load balancer in front of it, verifies the chain against that CA and then checks the common name — trusting the CA alone is not enough.

Meta's WhatsApp documentation suggests mTLS instead of allowlisting its IP addresses, which change periodically. Once mTLS is enabled on your WhatsApp Business Account webhook subscription, Meta presents the client certificate on every webhook request to your endpoint, and the check itself runs on your side — in your web server or load balancer. It complements X-Hub-Signature-256 rather than replacing it: every Meta app's webhooks arrive with a certificate carrying the same common name, so mTLS proves the connection came from Meta but cannot tell your app's deliveries from another app's — only the HMAC signature keyed with your app secret can.

Key takeaways

  • Webhook mTLS makes your endpoint demand a client certificate, so a connection that is not from Meta fails during the TLS handshake.
  • Trust Meta's CA file meta-outbound-api-ca-2025-12.pem and check the common name client.webhooks.fbclientcerts.com.
  • Meta's webhook client certificate now comes from a Meta-owned CA; the earlier DigiCert-signed one expired on 15 April 2026.
  • Meta suggests mTLS instead of IP allowlists because the IP addresses its webhooks come from change periodically.
  • mTLS authenticates the connection, not the payload: keep verifying X-Hub-Signature-256 on every POST.

Where does the mTLS check happen?

5 / 5

Stage 5 of 5 · Deliver

The recipient decrypts hop 2. Encrypted on every hop, yet readable in the middle.

At Your webhook app:messages: Is my order shipped?

Meta webhook serverssees

messages: Is my order shipped?
Can read itReadable in the app

Serversees

messages: Is my order shipped?
Can read itDecrypted hop 1 and can read it

Your webhook appsees

messages: Is my order shipped?
Can read itDecrypted hop 2

Can read the message

  • Meta's webhook infrastructure
  • Your load balancer, after verifying Meta's client certificate
  • Your webhook app

Cannot read it

  • Anyone watching the network on either hop
  • Proxies and Wi-Fi along the path
A webhook travels from Meta to your load balancer, which demands and verifies Meta's client certificate, then on to your app over a second TLS hop. Step through to see who can read it at each point.

Step 5 of 5, Deliver: The recipient decrypts hop 2. Encrypted on every hop, yet readable in the middle.

How does webhook mTLS work?

  1. Download Meta's CA certificate

    Get meta-outbound-api-ca-2025-12.pem from Meta's webhooks documentation and add it to the trust store your TLS terminator uses for client certificates.

  2. Require a client certificate

    Configure the endpoint to request and verify client certificates against that CA — in Nginx, ssl_verify_client on with ssl_client_certificate; on a managed load balancer, an mTLS listener with a trust store.

  3. Check the common name

    Accept only the subject CN=client.webhooks.fbclientcerts.com. In Nginx compare $ssl_client_s_dn; behind a load balancer, read the subject header it forwards, such as X-Amzn-Mtls-Clientcert-Subject.

  4. Keep the signature check

    In the application, still verify X-Hub-Signature-256 over the raw body with your app secret before processing anything.

  5. Plan for CA changes

    Meta announces new client-certificate authorities in advance. Add a new CA to the trust store while the old one is still valid, so the switch does not drop webhooks.

Webhook mTLS in code

server {
listen 443 ssl;
server_name wa-webhooks.example.com; # dedicated hostname for webhooks
ssl_certificate /etc/ssl/webhooks/fullchain.pem;
ssl_certificate_key /etc/ssl/webhooks/privkey.pem;
# Mutual TLS: require and verify Meta's client certificate
ssl_verify_client on;
ssl_client_certificate /etc/ssl/certs/meta-outbound-api-ca-2025-12.pem;
ssl_verify_depth 3;
location /webhooks/whatsapp {
# Trusting the CA is not enough: pin the client identity too
if ($ssl_client_s_dn !~ "(^|,)CN=client\.webhooks\.fbclientcerts\.com(,|$)") {
return 403;
}
proxy_pass http://127.0.0.1:3000;
}
}

Nginx answers clients without a certificate with HTTP 400 "No required SSL certificate was sent".

Why does webhook mTLS matter?

A public webhook URL receives traffic from anyone who finds it: scanners, fuzzers, attackers replaying captured payloads. Signature checks reject forged events, but only after your application has accepted the connection, read up to 3 MB of body and computed an HMAC. mTLS moves the rejection to the edge — clients without Meta's certificate never reach your code. For regulated businesses it also gives auditors a clear network-level control that, unlike an IP allowlist, does not break when Meta's address ranges change.

Key facts at a glance

Webhook mTLS: key facts and limits

Client certificate CN
client.webhooks.fbclientcerts.com
CA to trust
meta-outbound-api-ca-2025-12.pem (Meta-owned CA)
Previous certificate
DigiCert-signed, expired 15 April 2026
Where you check the CN
Nginx $ssl_client_s_dn or ALB X-Amzn-Mtls-Clientcert-Subject
Meta's suggestion
mTLS instead of IP allowlists (IPs change)
Still required
X-Hub-Signature-256 check on every POST

Common wrong turns

Common mistakes with webhook mTLS

  • Trusting the CA but not checking the name

    Verifying the chain only proves the certificate came from Meta's CA. Pin the subject to CN=client.webhooks.fbclientcerts.com, as Meta's instructions say.

  • Dropping the signature check

    Every Meta app's webhooks present a certificate with the same common name, so mTLS cannot tell your app's deliveries from anyone else's. Only X-Hub-Signature-256, keyed with your app secret, proves the event is yours and unaltered.

  • Missing a CA change

    When Meta moved off the DigiCert-signed certificate, an endpoint that trusted only the old chain would reject Meta's new certificate at the handshake and stop receiving webhooks. Follow Meta's developer changelog and add new CAs early.

  • Enforcing mTLS on a shared hostname

    ssl_verify_client on applies to every path in that server block, including health checks and other integrations. Give the webhook its own hostname or listener.

Example: Locking down a lender's webhook

A Jaipur microfinance lender's security audit flags its WhatsApp webhook URL as reachable by anyone on the internet. The team moves it to a dedicated hostname behind its load balancer, uploads Meta's CA file to an mTLS trust store and forwards the verified certificate subject to the app, which rejects anything other than CN=client.webhooks.fbclientcerts.com before checking X-Hub-Signature-256. Scanners now fail at the handshake and never reach the application, the auditor records a network-level control, and the IP allowlist the team had been maintaining by hand is retired.

Good practice

Best practices for webhook mTLS

  • Roll out with ssl_verify_client optional and log $ssl_client_verify first, then switch to on.
  • Alert on client-certificate failures at the load balancer — a spike after a Meta certificate change is the first sign of trouble.
  • Leave IP allowlists out of new designs; Meta changes its addresses.
  • Record the CA file name in your runbook so the next certificate change is a known task.

Webhook mTLS (Mutual TLS) FAQs

Does Meta support mTLS for WhatsApp webhooks?+
Yes. Once mTLS is enabled, Meta's webhook servers present a client certificate with the common name client.webhooks.fbclientcerts.com, signed by a Meta-owned CA, and Meta suggests mTLS instead of IP allowlisting.
If I use mTLS, do I still need to check X-Hub-Signature-256?+
Yes. mTLS proves the connection comes from Meta's webhook servers, but every Meta app's webhooks present the same certificate name; the signature, keyed with your app secret, proves the payload was sent for your app and not altered.
Why did my webhooks stop in April 2026 when I use mTLS?+
Most likely your trust store only had the old DigiCert-signed chain, which expired on 15 April 2026. Add Meta's CA file meta-outbound-api-ca-2025-12.pem and keep checking the common name.
Should I allowlist Meta's IP addresses instead?+
Meta suggests mTLS instead. The IP addresses its webhooks come from change periodically, so an allowlist needs constant maintenance and can silently block real traffic, while mTLS identifies Meta cryptographically.

See InfiQ pricing

Try it on the official WhatsApp Business API

InfiQ is an official Meta Business Partner. Start a 7-day free trial — no card needed — and see this running on your own number.