CTRLK

Build a two-way WhatsApp trivia agent with Azure Foundry, Infobip MCP, and automated memory

|

View as Markdown

As an outcome of this guide, you will build a two-way WhatsApp trivia agent that initiates conversations, generates questions, validates answers, and remembers everything. All is connected through webhooks and MCP.

A user opens WhatsApp and finds a message: "Hey Alex, reply with ready for next question to start a game of trivia!" They reply, and within seconds, a trivia question arrives. They guess wrong, the bot asks them to try again. They guess right, the bot congratulates them and offers the next question. Every question, every answer, tracked per user, across multiple simultaneous conversations.

The surprising part: all of this behavior is driven entirely by an LLM, based on instructions we provided. No application code, no state machine, no database schema. Just an Azure Foundry agent with memory, Infobip WhatsApp MCP server, and a carefully written system prompt.

This tutorial walks you through building it: a two-way WhatsApp trivia agent that initiates conversations, generates questions, validates answers, and remembers everything, all connected through webhooks and MCP.

Scenario overview [#scenario-overview]

The architecture consists of four components:

  1. Azure Foundry agent: drives the entire trivia game logic through its system prompt, uses automated memory to store questions per user.
  2. Infobip WhatsApp MCP server: sends and receives WhatsApp messages through the agent.
  3. Azure Logic App: receives inbound WhatsApp messages from Infobip and forwards them to the Foundry agent, including per-user memory scoping.
  4. Infobip subscription: routes incoming WhatsApp messages to the Logic App webhook.

The conversation flow works as follows:

  1. The agent sends an initial template message to the user on WhatsApp (required by WhatsApp/Meta policy).
  2. The user replies that they're ready.
  3. The agent generates a trivia question, stores it in memory, and sends it.
  4. The user submits an answer.
  5. The agent retrieves the stored question from memory, validates the answer, and responds accordingly.
  6. Repeat.
Two-Way WhatsApp Trivia Agent component diagram

Prerequisites [#prerequisites]

  • Azure account with access to Azure Foundry with a deployed LLM model (this tutorial uses GPT-5.6-Terra)
  • Infobip account with:
    • A WhatsApp sender (test sender included with free trial accounts)
    • An API key with the whatsapp:manage scope
  • Destination phone number to receive test messages. If in a free trial, you can only send messages to a verified phone number.

Limitations [#limitations]

  • The first outbound message to a user must use a pre-approved template.
  • If in a free trial, you can only send messages to a verified phone number.
  • After the initial template message, the conversation is "open" and the agent can send free-form text replies for 24 hours. Each user reply resets the 24-hour window.

Summary of the steps [#steps-summary]

  1. Create the agent in Azure Foundry.
  2. Add Infobip WhatsApp MCP server.
  3. Enable and configure memory.
  4. Understand WhatsApp template requirements.
  5. Write the agent instructions.
  6. Test the initial template message.
  7. Create the Logic App.
  8. Build the Logic App workflow.
  9. Configure Infobip inbound message subscription.
  10. Play trivia.

Step 1: Create the agent in Azure Foundry [#step-1-create-the-agent-in-azure-foundry]

  1. Open Azure Foundry and go to your project.
  2. Create a new agent under Agents > New agent.
  3. Name the agent, e.g., Trivia Agent and select your deployed model. GPT-5.6-Terra with medium reasoning effort handles this use case well. The logic is nuanced but not computationally heavy.
Agent name and model configuration

Step 2: Add Infobip WhatsApp MCP server [#step-2-add-infobip-whatsapp-mcp-server]

  1. Under Tools, add a new tool.

  2. You can leave the default Web Search tool enabled if you want the agent to look up trivia facts, or remove it to keep things focused.

  3. Search the catalog for Infobip WhatsApp MCP server and select it. The endpoint URL is pre-configured.

    Adding WhatsApp MCP tool from catalog
  4. For authentication, use API key with the format App <Your API Key>. You'll need an API key with the whatsapp:manage scope — create new one in the Infobip portal under Developer Tools > API Keys, and make sure this scope is enabled. Note the App prefix (including the trailing space), then your actual secret API key.

  5. Set tool approval to always auto-approve so the agent can send and receive messages without manual confirmation.

Step 3: Enable and configure memory [#step-3-enable-and-configure-memory]

This is what makes the trivia game possible. Without memory, the agent will forget every question it asked the moment the conversation ended. With memory, it can store questions, track which ones have been answered, and maintain separate game states for different users.

  1. Under Memory in the agent configuration, toggle it on and create a new memory store. When creating the memory store, you will configure an LLM for embedding and compression. Azure handles this automatically.

Memory scope [#memory-scope]

The most important setting is the scope. Make sure it is set to {{$userId}} (default value) to scope memories per user. This means each phone number gets its own isolated memory space.

Memory scope configuration

Without per-user scoping, all users would share the same memory. User A's trivia question would leak into User B's session. With user scoping, the agent maintains completely separate game states for each participant even when multiple users play simultaneously.

How scoping works [#how-scoping-works]

The Azure Foundry documentation explains two ways to set the user ID for memory scoping:

  1. Microsoft Entra authentication token: Foundry extracts the user ID from the caller's Entra identity. This will not work for our use case because the Logic App always authenticates with its own system identity, so all requests would share the same scope.
  2. x-memory-user-id request header: The caller provides an explicit user ID in a custom header. This is what we'll use: the Logic App will set this header to the WhatsApp sender's phone number.

Step 4: Understand WhatsApp template requirements [#step-4-understand-whatsapp-template-requirements]

Before writing the agent instructions, you need to understand a WhatsApp platform rule: the first outbound message to a user must use a pre-approved template. This is how Meta controls spam. Businesses cannot cold-message users with arbitrary text.

  1. From within your Infobip account, go to Channels and Numbers > WhatsApp to see your WhatsApp sender.

  2. Use a template to send a message. Trial accounts come with a test sender and several pre-approved templates. For this tutorial, we will use the connect_to_bot template, which has two placeholder parameters:

    Template message details

    The template reads:

    bash
    1"Hey {{1}}, reply to this message with {{2}} to start chatting with the chatbot you just created!"
    2 
    3 - `{{1}}` — we'll fill this with the user's name
    4 - `{{2}}` — we'll fill this with "ready for next question"

After this initial template message, the conversation is "open" and the agent can send free-form text replies for 24 hours. Each user reply resets the 24-hour window.

In production, you'd register your own sender number and custom templates through the Infobip portal. For development and testing, the pre-approved sender and templates in trial account work fine.

Step 5: Write the agent instructions [#step-5-write-the-agent-instructions]

This is the most elaborate part of the setup. Because the LLM drives all game logic, the instructions need to cover every scenario: initiating conversations, generating questions, handling correct answers, handling wrong answers, and managing memory.

Here's the structure of the instructions:

Introductions and basic overview [#introductions-and-basic-overview]

It is good to start with overview of agents role and expected behavior:

Agent instructions
1# WhatsApp Trivia Bot
2 
3You communicate with users through Infobip WhatsApp MCP server. Your responsibilities are to ask trivia questions and validate users' answers.
4 
5Before a significant MCP call, provide a concise preamble stating the call's purpose and its minimal inputs. After each MCP call, validate in 1–2 lines whether it succeeded. If it fails, do not assume delivery or state was saved, and self-correct or clearly report the limitation.

WhatsApp sender configuration [#whatsapp-sender-configuration]

Agent instructions
1## Sender Requirement
2 
3For every WhatsApp message, you **must** use the sender number `<use your sender>`.

Tell the agent which WhatsApp sender to use. You will find this number under your WhatsApp senders on the Infobip portal.

Initial outbound message rules [#initial-outbound-message-rules]

Agent instructions
1## Initial Outbound Messages
2 
3When sending an initial outbound message:
4 
5- You **must** send a template message.
6- Use the `connect_to_bot` template.
7- Set the first template placeholder to the user's name.
8- Set the second template placeholder to `ready for next question`.
9- Do not send an initial outbound message if the recipient's phone number or name is missing. Request the missing information rather than guessing.
10 
11Example:
12 
13{"messages":[{"from":"<use your sender>","to":"<users-phone-number>","content":{"templateName":"connect_to_bot","templateData":{"body":{"placeholders":["<users-name>","ready for next question"]}},"language":"en"}}]}

Once again, make sure to use your own WhatsApp sender in the JSON example snippet. This consistent repetition reinforces the importance of using the correct sender for the LLM that will receive these instructions

Reply handling: user requests a question [#reply-handling-user-requests-a-question]

Agent instructions
1## Replies to Incoming Messages
2 
3When replying to a message received from a user:
4 
5- Send a direct text message, do not use templates.
6- Use the sender number `<use your sender>`.
7- Address the reply to the user's phone number, which is the source of the incoming message.
8 
9### When the User is Ready for the Next Question
10 
11If the user reports that they are ready for the next question:
12 
13- Create a relatively easy trivia question for which you know the answer.
14- Save the question and its expected answer in memory.
15- Send only the question, without the answer, to the user's phone number as a WhatsApp text message.

Again, specify your sender in the instructions.

Reply handling: user submits an answer [#reply-handling-user-submits-an-answer]

Agent instructions
1### When the User Responds to a Trivia Question
2 
3If the user responds with an answer to a trivia question:
4 
5- Retrieve the latest question and expected answer from memory.
6- Check whether the user's answer matches the expected answer in memory.
7- If the user answered correctly, mark the question in memory as already answered and congratulate the user and ask them, through a WhatsApp text message, whether they are ready for the next question.
8- If the user did not answer correctly, ask them to guess again in a WhatsApp text message and retain the question in memory for the next iteration.

The elegance here is that the LLM handles all the nuance: fuzzy matching on answers (e.g. "Jupiter" vs "jupiter" vs "It's Jupiter!"), natural language responses, and conversational flow. You do not need to code any of this.

Step 6: Test the initial template message [#step-6-test-the-initial-template-message]

Save the agent and use the Preview chat to test the template message. Ask the agent to send an initial message to your phone number:

bash
Send the initial message to <your phone number>

Check your WhatsApp for the template message from the Infobip sender:

WhatsApp template message received

The message reads: "Hey Josip, reply to this message with ready for next question to start chatting with the chatbot you just created!"

Do not reply yet. The webhook is not set up, so the agent will not receive your message. That's the next step.

Step 7: Create the Logic App [#step-7-create-the-logic-app]

  1. Create a new Logic App resource in Azure.
  2. Enable System assigned identity under the Logic App Identity settings, then go to your Foundry resource > Access control (IAM) and grant the Foundry User role to the Logic App identity .

The Logic App authenticates to Foundry using its system-managed identity. No credentials to store or rotate.

Step 8: Build the Logic App workflow [#step-8-build-the-logic-app-workflow]

Open the Logic App Designer. This workflow has some additional complexity because of the bundling of messages submitted by Infobip's webhook logic and custom headers needed to scope memories on the Foundry agent side.

HTTP trigger with JSON schema [#http-trigger-with-json-schema]

Add a When an HTTP request is received trigger. We will need to specify a JSON schema for it. The Infobip platform can deliver multiple messages in a single webhook request (batched for efficiency), so the payload contains a results array.

You can generate the schema from an example payload. Select Use sample payload to generate schema and paste a sample:

json
1{
2 "results": [{
3 "from": "<sender phone number>",
4 "to": "447860099299",
5 "message": {
6 "text": "I'm ready for the next question!"
7 },
8 "contact": {
9 "name": "John"
10 }
11 }]
12}
Sample JSON payload modal for generating the HTTP trigger schema

The schema tells Logic Apps how to parse the incoming payload, making individual fields available as dynamic content in subsequent steps.

Invoke Agent action with dynamic content [#invoke-agent-action-with-dynamic-content]

  1. Add a new action and search for the Invoke agent action from the Azure AI Foundry connector.
  2. When creating the connection, select Managed Identity as the authentication type. This uses the system identity you configured earlier.
  3. For the Azure AI project endpoint, go to your Foundry project and copy the project endpoint URL from the overview page.
  4. Select the agent_reference type and pick your trivia-agent.
  5. For the Input field, use the dynamic content picker to insert the from field (the user's phone number) and the text field (the user's message). This becomes the prompt the agent receives.

Because you referenced a field from inside the results array, Logic Apps automatically wraps the Invoke Agent action in a For Each loop handling the case where multiple messages arrive in a single webhook request.

For Each loop with dynamic content from the results array

Add the custom memory header [#add-the-custom-memory-header]

The graphical designer does not support custom HTTP headers on the Invoke Agent action. Switch to the Code view to add it manually.

Code view with custom headers

In the JSON definition of the Invoke Agent action, add a headers property:

json
1"headers": {
2 "x-memory-user-id": "@{item()?['from']}"
3}

This sets the memory scope to the sender's phone number. Each WhatsApp user gets their own isolated memory. Their own questions, their own answers, their own game state.

Save and publish the workflow. Copy the generated webhook URL from the HTTP trigger.

Step 9: Configure Infobip inbound message subscription [#step-9-configure-infobip-inbound-message-subscription]

The Logic App webhook is ready, but Infobip doesn't know to send messages to it yet. You need to create a subscription that routes incoming WhatsApp messages to your webhook.

  1. From within the Infobip account, go to Channels and Numbers > Numbers and find your WhatsApp number.

  2. Check the number's inbound configuration under WhatsApp settings.

  3. Edit the inbound configuration to check that the forwarding action is set to Apply subscription, which means messages will be forwarded to the subscription we are about to create.

    Editing inbound configuration with Apply subscription forwarding

Create a subscription [#create-a-subscription]

  1. Go to Developer Tools > Subscription Management and create a new subscription.

  2. On the Category step, give it a name and select WhatsApp as the channel:

    Subscription creation with name and WhatsApp channel selected
  3. On the Events step, check Inbound message. This is the event that fires when a user sends a text message.

  4. Skip the Filtering step (receive all events).

Create a notification profile [#create-a-notification-profile]

The subscription needs a notification profile that defines where to forward messages. Create one with your Logic App webhook URL:

Notification profile with webhook URL

Save the subscription, then go back to your WhatsApp number's inbound configuration and verify the subscription you just created is used in the inbound action.

Step 10: Play trivia [#step-10-play-trivia]

Everything is wired up. Go back to WhatsApp and reply to the template message you received earlier. Type "I'm ready for next question!"

The message travels from WhatsApp to Infobip, through the subscription to your Logic App webhook, into the Foundry agent, which generates a question, stores it in memory, and sends it back using the WhatsApp MCP server.

Trivia question received on WhatsApp

The agent will come up with a trivia question on its own. It can be anything from geography to science to pop culture. Try submitting a wrong answer first. The agent checks its memory, finds the stored answer does not match, and asks you to try again. Then submit the correct answer. The agent confirms you're right and asks if you're ready for the next round.

Correct answer and next question flow

Inspect the memory store [#inspect-the-memory-store]

Back in Azure Foundry, go to Memory and open the memory store. Enter your phone number in the Scope field to filter memories for your user, and select Chat summary as the Kind. This is where the agent most likely stores trivia questions and answers.

Memory overview in Foundry

Select individual memory entries to inspect their content. You will see the trivia questions the agent generated, along with the correct answers it stored for validation. Each entry is scoped to your phone number, so different users have completely separate memory spaces. The specific questions your agent generates will differ from what's shown here as this is the nature of LLM-driven interactions.

What you've built [#what-you-built]

This trivia agent demonstrates several concepts working together:

  • Two-way messaging over WhatsApp: using Infobip WhatsApp MCP server the agent both sends and receives messages
  • WhatsApp template compliance: the initial outbound message uses a Meta-approved template, then the conversation switches to free-form text
  • Per-user automated memory: each user gets their own memory scope, allowing the agent to track questions and answers independently across multiple simultaneous conversations
  • Webhook-driven architecture: Infobip subscriptions route inbound messages to Logic Apps, which invoke the Foundry agent with the right context and memory scope
  • LLM-driven application logic: the entire game (question generation, answer validation, state management) is defined in the system prompt, not in application code

The most striking aspect is how much behavior emerges from the instructions alone. The agent decides what questions to ask, judges whether answers are correct (with natural language understanding, not string matching), manages conversational flow, and maintains state across interactions. All of this runs autonomously once the webhook pipeline is connected.

Next steps [#next-steps]

  • Richer content: Use WhatsApp interactive message types (buttons, lists) through the MCP server to offer multiple-choice answers instead of free-form text
  • Scoring system: Extend the memory to track scores: correct answers, streaks, total questions answered — and send periodic leaderboard updates
  • Multi-channel: Add SMS or RCS as fallback channels for users who do not have WhatsApp
  • Custom templates: Register your own WhatsApp templates through the Infobip portal for a branded first-message experience
  • Production hardening: Add error handling in the Logic App workflow, implement retry logic for failed agent invocations, and set up monitoring dashboards for webhook delivery rates
Was this page helpful?