Live Webinar
The Festive Growth Sessions: How Top Brands Drive More Leads· 23 Sept, 3:30 PM ISTSave Your Seat
Wati

How to Give an AI Agent Read-Only Access to Your WhatsApp Inbox

Krithika M
6 mins read
Fact-checked by: Namitha Sudhakar
|According to: Editorial Policies
Banner showing an AI agent with a read-only WhatsApp token that can read customer messages in a team inbox but cannot send replies.
CategoriesAI Agent

Too Long? Read This First

  • Hiding a tool from tools/list is defence in depth, not access control. Enforce authorization inside every tool, too.
  • Give the reporting agent its own credentials. A reporting token should be rejected by a sending tool even if one is added to that server later.
  • Meta splits permissions two ways: whatsapp_business_messaging covers sending and inbound message webhooks; whatsapp_business_management covers account metadata, templates, and analytics.
  • "Read the conversations" normally means querying an auditable store you populated from webhooks, not an open transcript search endpoint.
  • Log every authorization decision. Do not log bearer tokens, and keep message bodies out of operational logs.

If you want an agent that reports on conversations without ever messaging a customer, do not rely on telling it to behave.

Build a server profile that exposes only read tools, and issue it a token that lacks every sending scope, so a send is impossible rather than merely discouraged.

This comes up constantly once a team gets past the demo stage. Someone wants weekly conversation analytics, a quality audit, or a look at why response times slipped, and nobody wants that analysis to carry any risk of an accidental broadcast.

In this guide, we cover how to design a read-only tool profile and scope set that actually holds up, what Meta's permission model does and doesn't let you separate, and the logging you need to make the whole thing auditable.

Design the Profile Before Setting Scopes

The instinct is to start with OAuth scope names. Start instead with the tool list, because that is what the model sees.

A read-only profile exposes discovery and retrieval: listing conversations, fetching messages, checking message status, reading contacts, and reading account metadata.

It does not expose sending, media upload, template management, account configuration, or webhook management. Not "exposes them with a guard", does not expose them.

Then enforce it twice. The MCP tools specification treats tool visibility as a presentation concern, so omitting a tool from the list keeps the model from choosing it, but does nothing about a caller that constructs the request by hand.

Every tool still needs its own server-side scope check and object-level authorization on the tenant, account, and phone number involved.

Credential separation is the part that teams skip. If reporting and operations share one token, then the day someone adds a send tool to that server, your read-only agent silently gains the ability to message customers.

Separate credentials make that a deliberate act rather than an accident.

Design Scopes That Hold Up

OAuth 2.1 scopes are space-delimited, case-sensitive values defined by your authorization server. The client asks for a set, the server returns what it actually granted, and the resource server validates the token's expiry, audience binding, and whether the granted scope covers the operation.

Scope

Covers

In a reporting profile

wa:account:read

Account and phone number metadata

Grant if needed

wa:conversation:read

Inbound messages and conversation data

Grant

wa:status:read

Delivery, read, and failure events

Grant

wa:analytics:read

Analytics data

Grant if needed

wa:messages:send

Sending messages

Never grant

wa:templates:manage

Creating and editing templates

Never grant

wa:account:manage

Account and webhook configuration

Never grant

Scope names are not standardized, so document what each one means and keep a tool-to-scope policy that the server actually consults. A scope claim alone should never be the whole decision: check the tenant, the WhatsApp Business Account, the phone number, and the specific conversation, too.

Two details from the MCP authorization specification are easy to miss.

Tokens go in the Authorization: Bearer header and never in a query string, because URLs end up in logs, proxies, and browser history. And tokens must be audience-bound to the resource server, so a token minted for your MCP server cannot be replayed against a different service.

When a token is valid but under-scoped, return 403 with an insufficient_scope challenge rather than quietly doing something narrower.

Silent degradation teaches the model that the call succeeded.

What “Read Access” Means on WhatsApp

This is where a generic MCP design meets Meta's actual permission model, and the mismatch matters.

Meta's Permission Model

Meta separates messaging access from management access.

Permission

What it covers

WhatsApp Business Messaging

Sending messages, receiving inbound messages, and status webhooks

WhatsApp Business Management

WhatsApp Business Account metadata, template management, associated phone numbers, and analytics

Note the awkward consequence: receiving inbound messages sits under the messaging permission, the same one that allows sending.

You cannot request "inbound only" from Meta.

The read-only boundary has to be enforced in your own layer, which is another reason the tool profile and scope design carry the weight.

What the Webhooks Provide

What arrives in those webhooks is also worth knowing before you promise an audit trail.

Meta's webhook payloads can carry:

  • A profile name and WhatsApp ID
  • The sender
  • Message ID
  • Timestamp
  • Message type and content, such as text
  • Status events for outgoing messages, including sent, delivered, read, played, and failed

What About Historical Conversations?

There is no general endpoint that returns every historical transcript on demand.

Meta documents a history webhook for synchronizing WhatsApp Business App chat history when a business is onboarded by a solution provider and has agreed to share it.

The documented history covers:

  • Messages within 180 days of Cloud API onboarding
  • Excludes group chats
  • Additional media limitations

Treat that as a consented, bounded sync, not a blanket read guarantee.

The Practical Architecture

So the honest architecture for conversation reporting is:

WhatsApp → Webhooks → Validate → Persist → Read-only MCP tools → AI agent

Subscribe to the webhooks, validate them, persist the permitted events into a store you control, and point the read-only MCP tools at that store.

Use Human Approval Where It Matters

Confirmation prompts are useful, and they are also the wrong primary control for this problem.

For an audit-only agent, do not put a confirmation step in front of a send tool. Remove the send tool and the scope. A confirmation dialog depends on a human reading it carefully every single time, which is a weak guarantee compared with an operation that cannot be authorized.

Keep approval for the decisions where a human genuinely adds judgment: connecting the agent to a new account, enabling a new data source, running a bulk export, generating a cross-customer report, downloading media, or changing retention settings.

Make the approval screen name the server, the account, the phone number, the tool, the requested scopes, the data range, and the destination, so the person approving knows what they are agreeing to.

Build Logging That Survives an Audit

Record every authorization and tool decision: timestamp, authenticated principal, client identity, server, account, and phone number scope, tool name, requested scopes, granted scopes, resource identifiers, the allow or deny result, any error, the human approval or denial, and a correlation ID. Log webhook event IDs and processing outcomes so any figure in a report traces back to source events.

Then be disciplined about what does not get logged. Never log bearer tokens. Redact or hash phone numbers where you can. Keep full message bodies out of operational logs and in a separately protected store with explicit retention, encryption, and deletion rules. Flag scope elevations and exports prominently, because those are the high-value events an investigation will look for.

The walkthrough in auditing a WhatsApp AI agent in Claude shows what this looks like from the reviewer's side, and the broader control set is covered in MCP security for WhatsApp AI agents.

On Wati's MCP server, each connection authorizes against the user's own account, so permissions can differ per connected assistant. That is the difference between handing out one shared key and granting a reporting agent exactly the reads it needs.

Make Read-Only Access a Real Permission Boundary

Giving an AI agent access to your WhatsApp inbox doesn’t mean permitting it to send messages.

The safest approach is to expose only the tools it needs, enforce read-only scopes at the server, and keep reporting credentials separate from sending capabilities.

With Wati’s MCP server, you can connect an AI assistant to WhatsApp through OAuth and control access based on the connected account’s permissions.

Want to see how it works? Book a Wati demo to explore read-only WhatsApp access for AI agents.

Frequently asked questions

Can I just tell the agent in its system prompt not to send messages?

You can, and you should not rely on it. A prompt instruction is a preference, not a permission boundary, and it fails against prompt injection in an inbound customer message. Remove the capability instead.

Does Meta offer a read-only WhatsApp permission?

Not in the way people expect. Receiving inbound messages requires whatsapp_business_messaging, the same permission that allows sending. Your read-only boundary has to live in your own scope and tool layer.

How do I let an agent read conversation history?

Populate a store from webhook events and expose read tools over that store. There is no general historical transcript endpoint, and the documented history webhook is a consented onboarding sync bounded to 180 days.

Should read tools require human approval too?

Individual reads, generally no. Bulk exports and cross-customer reports, yes, because volume changes the privacy impact even when each record was already readable.

What happens if a valid token asks for a tool it lacks scope for?

Return 403 with an insufficient_scope challenge. That tells the model it hit a permission boundary, which is far more useful than an empty result it might interpret as "no data found."

Related posts