Knowing which customer is asking
Whether a tool needs to know who's asking — and if so, how strongly to verify them — is a short decision you set up once, per tool. This is the ladder from anonymous to fully signed-in.
The decision, in three questions
For any capability you expose as a tool, walk these once at design time:
- 1Is identity even needed?Public info (prices, stock) or a reference-gated lookup (“track by tracking number”) needs none. Personal → continue.
- 2Is the action sensitive?Low-risk personal (“where’s my order?”) → the phone is enough. Reveals personal/financial data, or changes something → step-up required.
- 3Which step-up — a code or a login? Decided by your architecture, not by how secret the data is (next section). And for high-risk, irreversible actions, re-verify every time.
Tiers 1–2: from public to phone-as-identity
Every tool call carries the customer’s WhatsApp number — Meta verified they possess it, we received it on a signature-verified webhook, and we forward it HMAC-signed. It arrives in context.contact_phone and the X-MCP-Contact-Phone header, as digits with no +.
It only identifies someone if the number is on file
The phone matches a customer only when you key customers by phone and they message from the same numberthat’s on their account. So: collect a phone at signup, tell customers to message from their registered number, and treat a no-match as “not identified yet” — the one-time code below is how you connect a mismatched or missing number.
Is this action sensitive?
You classify each tool — it’s domain-specific, and only you can judge it safely. A simple rule to adopt and refine:
- Not sensitive — public info, and lookups gated by a reference the customer holds (order/tracking number). Phone-match, or nothing, is fine.
- Sensitive → step up— anything that reveals personal or financial data tied to identity (balance, saved addresses, “my order history”), or that changes state (update details, cancel, pay, redeem).
Enforce it where the data lives — in your tool endpoint. For a sensitive action from a contact you haven’t verified, return a soft verification_required result rather than the data; the agent takes it from there.
Verifying identity: the one-time code (start here)
This is the defaultway to authorize a sensitive action — and the way to connect a WhatsApp number you couldn’t match. It works whenever your backend can serve the customer’s data from a trusted server-to-server call once it knows who they are — which is most businesses. You only confirm identity once; no customer token is involved.
- 1Your tool returns
verification_required. The agent offers to verify: “I can send a code to the email on your account — shall I?” - 2You send a one-time code to the customer’s on-file email or phone (your channel, your template).
- 3The customer types the code in chat; the agent passes it to your verify tool.
- 4You confirm the code, link this WhatsApp number to the customer, and the original action retries — now served from your own records.
Connect your existing login (Preview)
If your API is genuinely login-guarded per user, the fix isn’t a code — it’s the customer’s actual session. The good news: your app’s own API is already the tool surface, so there’s little new on the data side. The one new piece is a token handoff:
- 1The agent offers a Sign in button that opens your own login page, carrying a signed, one-time, expiring
link_tag. - 2The customer signs in as they always do — passwords stay on your page.
- 3On success, your backend POSTs the token (and a refresh token) to our callback.
- 4We store it encrypted per (account, customer)and attach it on that customer’s tool calls; we refresh it to keep them served, and only re-send the button on a hard expiry.
/v1/identity/link) and token-lifetime details here are a working draft, not a finalized contract. Treat the shape as illustrative until this ships.High-risk actions: always re-verify
For irreversible or money-moving actions — a transfer, changing the login email or password — re-verify every time with a fresh code, even if the customer is already linked or logged in. A persistent link or a live session is only as strong as its weakest moment; a fresh check per high-risk action is the norm (banks do exactly this). Flag which of your actions count as high-risk.
Which do I use?
- Not sensitive → nothing, or phone-match.
- Sensitive, and your backend can serve by customer once identified → one-time code (the default).
- Sensitive, and your endpoints require the customer’s own token → login relay (Preview).
- High-risk / irreversible → fresh code every time, on top of the above.
You decide this once per tool, by how your API is built — not per conversation. The agent just runs whatever each tool asks for. Authenticating your integration (the API key) is in Authentication.