Recently, I realized that people are not always very clear about Dialogflow's architecture. In particular, a client was mixing up fulfillment and integrations. So this article provides a high level overview of Dialogflow's architecture with a focus on how data flows when users interact with Dialogflow agents.
In my view, there are 4 concepts you need to understand to get a good picture of Dialogflow's architecture.
You can summarize a Dialogflow agent as a series of (request, response) pairs  . That is,
1 User sends a request to the Dialogflow agent
2 (some NLU magic happens)
3 Dialogflow sends a response back to the user
Why is this important?
You see a lot of questions on forums on how to send "push notifications" from Dialogflow agents to the end user. (E.g. send them a reminder via Facebook messenger based on a past conversation). The request-first and response-next paradigm means that this feature isn't supported in Dialogflow and the only way to achieve push notifications is by sending "out of band" messages.
The second concept you need to understand is intent mapping.
Once your Dialogflow agent receives the user's request, it will try to map it to a list of pre-defined intents. Intents are created by the bot developer as a way of telling the Dialogflow service "here is a list of tasks that the user might ask the chatbot to do".
To understand how the intent mapping actually works, you need to understand some supplementary concepts - entities, contexts, parameters etc. You can take a look at my step by step guide to help you with this.
After Dialogflow maps the user's request to one of the pre-defined intents, it will send a response (which is also specified by the bot creator) back to the user.
Once Dialogflow maps the user's request to one of the pre-defined intents, it might have to perform some business logic before sending a response.
Instead of creating "business logic LEGO blocks" (which some other bot frameworks do), the Dialogflow folks decided to use a concept called Fulfillment.
Here is how it works:
1 Dialogflow understand the user's request and extracts structured information from their message
2 The structured information is sent to some code running on some web host which is maintained by the bot creator - this code is called a webhook 
3 The webhook performs the necessary business logic
4 It will return a response to your Dialogflow agent in a specific format
5 Dialogflow will parse the response, extract relevant information and use it in the response sent to the user
In addition to the features above, Dialogflow also exposes an API.
This API allows you to programmatically send requests to your Dialogflow agents. The request will be mapped to an intent and an appropriate response will be sent to the API caller, just as if the request message was typed into Dialogflow's console.
This means you can "embed" a Dialogflow agent into your existing applications and services.
Putting it all together
Let us consider Dialogflow's built-in web demo integration. If you would like to see it in action, check out this chatbot which gives advice on SEO. This is using the built-in web demo integration provided by Dialogflow. However, the web demo integration has a lot of limitations (e.g. cannot display formatted text, line breaks, images etc).
So you can integrate your website with a Dialogflow chatbot using its REST API, and get a more visually appealing chatbot. For example, my SupportBot supports images, text formatting, line breaks, buttons, list selectors etc.
When the user interacts with my SupportBot, this is how the data flows:
Have any questions about this diagram? Leave a comment below.
 There are some exceptions. For example, it is possible to trigger a response from your Dialogflow agent by using Events. Technically, this is still a "request" going to the agent's API endpoint, but it is not in the form of spoken or written text.
 If your business logic is quite simple, you can host your code right inside your Dialogflow agent by using "inline webhooks". But the idea is the same - instead of you hosting the code, you are letting Google host the code for you