📱

Get Our Mobile App

Take your business learning on the go!

Download on the App StoreGet it on Google Play

The only video you need to Master N8N + AI agents (For complete beginners)

Simon Scrapes | AI Agents & Automation4:04:47

Transcription

This is the only video you'll need to get started with n. It will take you from a complete beginner all the way through to a master. Whether you're a business owner who wants to implement AI, automate your work, and earn back your time, or you're someone who wants to build and sell AI automations to other businesses, this is the video I wished I had access to when I first started my automation and AI journey.

Back then, I wanted to take advantage of this new tech and implement it within my own business and my personal life, but most importantly, I didn't want to get left behind. But the problem is, I got overwhelmed very, very quickly. There was too much stuff out there; some of it was useful, but most of it was unnecessary, overhyped, and just a bit complicated.

Only after making hundreds of workflows within n, and getting a top-rated Upwork profile for selling AI agents and automation to other businesses for all sorts of tasks—email inbox agents, content creation agents, invoice management agents, and many, many more—I got to see which workflows were actually useful for businesses and which ones they were willing to pay for. I made this video to help you shortcut your path, save you a lot of time and headaches, and share with you only what works today. So get your notes ready, and let me show you exactly what we'll be covering in this course.

We'll be starting from the basics with what is n and why would you choose n over other alternatives. We'll be covering if you need to know how to code—hint: you don't; it's all no-code and easily accessible for everyone. We'll be covering what you can actually build for your business with a tool like n and how to actually set that up. We'll then be mastering the basics, learning how to work with different data and building out your very first automation. We'll then be working with data from your business, working out how to handle different file formats, but also building out your very own invoice processing agent that you can use every day in your business.

And it wouldn't be a good course for n if we didn't cover AI and how to use that in your workflows. So we're going to be breaking down exactly what is an AI agent versus something like ChatGPT, and what useful things can we build for your business using these AI agents to help you every day. We'll then be going on to some more advanced techniques of gathering data from outside your business, covering from scratch what is an API, when would I need one for my business, and how to connect to any data source that you need in less than 2 minutes. And finally, we'll be talking about how to make your life incredibly easy, talking about techniques for scaling our workflows and making them reusable with a modular design, as well as all the shortcuts that I've learned over my journey.

As you can see, whether you're a complete beginner or somebody already using n, this video will help you advance and get even better. So I encourage you to use the chapters within the video to skip to your current level. And by the way, for those of you who are more serious about implementing AI within your business, this course is a part of my paid School Community. Inside, you'll find a network of over 300 entrepreneurs on exactly the same journey as you, from all over the world. You'll find a template library of n workflows that you can implement inside your business today, and many more resources to help you shortcut your path even more. So if you feel like that's you, you can check out the link in the description of the video or go to school.com. SLS scrapes. But for now, let's get started with the course.

So getting started, we're going to be talking about workflow automation. Now, simply put, workflow automation is about getting technology to automate your repetitive tasks. So we've got a few examples before we go to n and understand what that does there. But say a customer is filling out a form on your website; it might automatically send them a confirmation email and then automatically add them to your database. That is a workflow that's been automated. Therefore, workflow automation. When you receive an invoice and it's automatically sorted, processed, and sent for approval, again, just another process that's been automated. When you have a new employee that you need to onboard, they join; their accounts and access are automatically created based on their role in the company—again, a really clear example of something that has been automated already within your business. But we can automate so much more, and we can do it ourselves really simply using something like n.

And the main benefits, if they're not already obvious, are: it saves you time and reduces your manual workload; there are fewer human errors; and we can get consistent results every time because a computer's doing it for us. And it takes away all the mundane work that we have to do day-to-day, and it allows you to focus on the important tasks within your business—not the ones you don't want to be doing.

So n is just a workflow automation platform, and there are a few commonly known platforms out there. It enables you to connect to all your favorite services that you currently use within your business, so that might be Slack, Trello, Google Sheets, Outlook, Intercom, your database. It has over 400 pre-built integrations, which mean we don't have to build anything from scratch. If, for example, you wanted to post to LinkedIn—this is inside an n workflow which we'll get to—but you can see they've got a pre-built integration with LinkedIn, so it's plug and play; we don't need to code anything; we can just connect it to our LinkedIn account and tell it what data we want to send.

You might have seen some alternative services or use them already, such as Zapier or Make.com. All of these are viable solutions to build out your workflows, but there's some key differences or key benefits that n offers over the alternatives, and that's why we've chosen n. Firstly, pricing. We're just going to compare something like Zapier to the n price. At the basic level for Zapier, you're going to be spending $30 per month, and you have restrictions on what you can use in terms of functionality. If you're a bigger business and start to use more tasks per month, it's going to really, really add up, and you're already at $200 per month without all of the features. Make.com is cheaper than Zapier in terms of pricing, but again, we have limited functionality in Make.com versus n8n. When I see Make.com automations posted, they're often looking like this, with a lot going on, and then I see comparisons of n flows built with a better feature set, and actually, you could build something like this in fewer steps. So it makes n far more flexible. And then in terms of pricing, it's the cheapest option out of the lot. Firstly, you can set it up directly on n for £24 a month and have 2,500 workflow executions, so that's 2,500 tasks. And secondly, n uses a sustainable use license, which means we can actually host it ourselves, and for unlimited workflow executions, it comes in around $15 to $17 per month—so significantly cheaper, and the feature set is far more advanced to do things in fewest steps.

N is a no-code software, so you don't need to know any coding to start this course and build your first automation. And from day one, you can have useful things running automatically for you, for your business. So you might be wondering at this point, what could I actually build with something like n? The list is endless. Here on screen is a picture of a LinkedIn and Twitter post generator, so it automatically creates all the content my business needs and posts it to the relevant platforms. I get to approve that in my database, exactly on my terms. Here, in just seven steps, is an example of a workflow automation that monitors my inbox for customer queries, and any that need escalation, it sends a direct message to me in order to feedback what I want to say and reply to the customer. That feedback is then drafted automatically for me, so I can just push send in my inbox. We have other examples that create and write a blog automatically for us based on tailored SEO keywords and a complete invoice management system that you're going to actually build out in this course, step by step. The possibilities are endless in terms of what you can build out for your business; you just need to take the first step and get started.

So let's talk now about hosting and how to set up n. So we're going to talk about the two options for hosting here. The first is hosting directly through n. So if you are happy to use my affiliate link, then go to n.p partner links. scrapes a and come to n's homepage, or alternatively go to n8n.io. You're going to land on this uh homepage here, and what we're going to do is we're going to run through the sign-up process of getting started for free, and you get a 14-day free trial directly through n. You're going to fill out all of your details and give it an account name, like your business name. You're then going to start the 14-day trial, and once that has completed, you'll be put onto the starter plan, which is around £24 a month. This is the most straightforward way to get set up. However, self-hosting has other benefits and is really, really simple to set up if you follow the steps provided. We can do it in under a few minutes.

So think of self-hosting as your n service being hosted on your own computer, but on a server somewhere in the world. So it means that you don't have to keep your laptop or computer on all times, but your automations will continue to run 24/7. When we sign up through n directly, they're just using a server, and we're hosting through their server. If you're self-hosting, you're just doing the same, setting up your own server elsewhere. Now, sometimes that comes with having to manage the infrastructure, but I found a service called ls.io, which we're going to set up now, that fully manages all the infrastructure. So you get the benefits of the low cost of self-hosting—so unlimited workflows for around $15 to $17 per month—but they also have the benefits of managing the infrastructure for you. So it automatically updates the software; you don't have to worry about any changes; it will do that all for you, and we still get the benefits of the low cost and the community features that come with it. So you're going to go to ls.io, and you're going to set up an account there. Once you set up an account, you'll come into a dashboard like this, and you'll have no services here. We're going to go and create a new service in the top right, and thankfully they've already pre-set up an n service for us, so it takes away all the technical details. So we're going to select n there. We have the options of different service cloud providers; we're just going to click Hetzner because it's the cheapest and reliable, and then choose the region that's closest to you. It will automatically pick that for you, so leave it like that. We then need to select a service plan. Don't worry about the details here; this basic plan, the cheapest plan, is definitely good enough for your business when you're starting out. I run hundreds of workflows on my server and still have this medium-sized service plan. On the right-hand side, you can see the estimated monthly price of $15, and we're going to hit next on that. We then want to give it a name, so we'll give it a name that makes more sense for us, an admin email, and then we'll stick with level one support. Later in the course, we'll talk about backups and error handling and all that, but we don't need any extra from ls.io, so we're going to go down here and click create service. Now that's going to deploy our service; it'll take between 1 and 5 minutes depending, and you're going to come back, and we'll load it up. We're going to come back here, and you can see now 5 minutes have gone, but the service is now running, and it's shown green here. So we're going to click into that, and then we're going to display admin UI, and this has all the details about your server. So if you ever need to change anything, you'd come to this dashboard. So we're going to click on the link that it provides under that, and that's going to open up the n page to sign up. So we're going to fill out the details here, and then we'll hit next, and that is basically it for setting up your own self-hosted server—so incredibly easy. We're just going to fill out the survey for n there. You get three additional paid features forever if you register your community edition, and they're really helpful, and we touch on them later on in the course. The first is getting workflow history, which we know; version control is very important, advanced debugging, and then you're also able to search your past execution log. So I definitely recommend uh getting that free license key and registering that because those features are really helpful, and we'll touch on them later. You then come into the dashboard for n, so this is where you start by creating your own automations. A personal preference of mine is changing the theme, so I go down here to settings, go to personal, and then in here we can change it to light theme, and I just think it's a bit more aesthetically pleasing. And that is it; you've set up your very own self-hosted instance of n, and it's always going to be hosted at this address, so you can come back and access it with your username and password, and this is going to continuously run your automation whilst you sleep.

What we're going to move on to now is navigating the dashboard here and working through the basics step by step to create our very first automation. N is a workflow automation platform, and what that means and what that enables is us to automate pretty much any of our work by connecting different softwares visually on a workflow. So I'm going to run through first the different fundamental building blocks of n, which are workflows, credentials, and executions. You'll open up your n environment in a screen like this, and what you'll see is an overview on the left-hand side, and that's where we store all of our flows. As you can see down here, we've then got a link to the n templates, which we'll cover later. As another tip, we've got variables; don't worry about that for now, and then we've got some help and support section. The first thing you're going to come across here are the workflows, credentials, and executions. You can think of workflows as the logic that connects all of our different software pieces. The credentials are just our keys, so how do we get into each of those softwares? We need our password; we need our username, so that is where your credentials are stored. And then you can think of executions as our history of all of the logs. So when we execute our logic, we need our keys to make sure it works and that we get into the right accounts, and then the executions show us our history of all previous workflows that have run, including the errors and those successful as well. Understanding those fundamental building blocks will help you build out your workflows and connect all your software. We're going to jump in now to an actual workflow, so we'll hit workflows on the top here, and what we're going to do is you'll probably see an empty screen here. We're going to go to create workflow up in the top; that's going to open what we call the canvas, and there's a few key important details here. We've got the name of our workflow here, which we can come in and edit, so we're just going to say test workflow, but you want to be whoops, you want to be as descriptive as possible as to what the workflow is doing. We've then got some tags, so tags enable you to easily filter and search through your workflows. So, for example, on this one, we're going to tag it with demo, and if we go back, we've saved it; we'll go back; we can see it's got the tag on demo, and we're able to filter here by the demo tag. You can see our new workflows appeared on our home screen here, and to get back into it, it we can click into it. So when we are in the canvas here, we have a few different other options; we have the editor mode where we can create visually our workflows, which we'll start doing in a moment, and then we have our executions, which show us all of the history or the executions we spoke through before of this workflow, so individually in a workflow, you can see all of the previous executions and look through whether was successful and what data was sent. It's a really powerful feature. If we go back to editor, there's a few more things here. If we make a change to the canvas by adding a first step, it will prompt us to save in the top right corner, or we can hit command or ctrl S to save. We then have a test workflow feature at the bottom, and we'll cover this more later, but we can hit test workflow, and if we test that, it will run our current workflow that's saved in the environment on the canvas. Now, when you come in here for the first time, it's easy to get overwhelmed with the number of options available. We're going to break them down now into four key categories. These four key categories will make it really simple for you to understand how to build out your first workflow. If we come back to this blank canvas here, so delete any nodes we've got on there, then we can add a first step, or we can click the plus to open the nodes panel here, or alternatively we can just hit tab on our keyboard; that opens up the options for the first node. A node is just an event taking place on a canvas, so that could be how we activate a workflow first. So we always going to need to activate workflow somehow, whether that be a manual trigger, so we'll open up the manual trigger, and the manual trigger is mainly for when we are testing things. This just means whatever is attached to this first manual trigger node will always become activated when we hit the test workflow button. There are other ways to trigger a flow, and that will be the ways you use in production. So we might have on an app event where we've got different software that could trigger, so for example, Airtable has a trigger on new Airtable event; whenever something happens in Airtable, that will trigger a corresponding reaction to whatever we connect this to. We'll remove the Airtable node and we'll go back to the triggers; we might want something to run once daily, so we can add a schedule trigger and determine inside the trigger itself how often or how frequently we want it to run. If we remove and go back to the triggers, we're now getting to the less frequently used triggers, but also important on a webhook core. Now, this may not make sense immediately, but we can pass data from an external service to activate our workflows, and that's what a webhook is, and we will go into full detail later on APIs and webhooks and how to use those; they're not as complicated as they seem. And then we've got a few other triggers on a form submission, so n actually allows us to submit a form through its user interface that starts off a workflow, and we'll pass in the details from the form. We can activate workflows from other workflows, so we can trigger one workflow from another; that's really important for scalability and reusability in our workflows, and we'll cover that later. And then finally, we've got on chat message, so we can actually have a chat window in the screen, and we can type a message in here, and it will activate workflow here. Once we have a trigger, so we'll put just put in the trigger manually as we're testing for now. The node will enable you to connect to other nodes; that's where we come on to the second element of this, which is action. Actions are how we connect to all of our business software, so we might use Google Sheets or Outlook or Slack or Notion; we need to take an action to connect to our business systems. And as you can see on n's integration page, they they have pre-built 1228 integrations, and then any that are not pre-built already, we're able to connect to their API, and that makes us effectively able to connect anything to everything—really, really powerful software for all of your business needs. We're going to go through some of the key actions in a moment, but the first action is connecting to a platform that we're using in our business. So back in the n canvas, we have our trigger, and now we're going to connect some actions and see what actions are possible. So when you open up the nodes window here, we have different categories; we have advanced AI, which we're not going to cover right now; we have action in an app, so what we just covered was that we can connect to any of these apps; we have data transformation, so this is a specific action that takes place on the data we're using, so for example, we might take data from our Google Sheets and manipulate that by adding some data or removing some data or stripping out some formatting of some data; that is what the data transformation nodes are for. And then within flow, we're able to also execute conditional logic, and what that means is if our data meets certain conditions, we can branch it and take an action on it; if it does not meet certain conditions, we can take an entirely separate action, so it means we can interact in the canvas with the data from our software that we're using in our business. We then have some core nodes, so these core nodes are just made up from these four categories anyway, and they just contain some of the most popular used nodes, and then newly we have human in the loop, where we're able to get feedback from a human when we're using AI. Finally, it gives us the option of multiple triggers, which we will cover later, but this gives us the option to add a second trigger into our workflow, so that not only can we have a test workflow trigger, but we might have a scheduled trigger; we might have a when executed by another workflow trigger, so there could be multiple ways to trigger our workflow, and all of them can be active at once. The fourth tip is around connecting easily to any of our software platforms. This is the easiest way to do it, so we're going to hit tab again to or hit across and open up an app, and for the example, we're going to use Airtable, so we know we use Airtable frequently, so we're going to click on the Airtable node. We have now got to select the action, but this doesn't restrict you from changing the action in future, but for the sake of the demo, we want to search our records in order to pull all of our records from the data, and there are other actions that we can take. So if I go back to the canvas here, you can see that this is totally not connected to our test workflow, so if we were to run test workflow, it's not going to run Airtable node, so what we need to do is just click the cross and drag it over to Airtable. The next part is how how do we actually connect to an Airtable that's outside of n, and so you can see on the left-hand side we've got inputs here, in the middle we've got our software that we want to connect to, so Airtable, and we make transformations in the middle here, and then on the right-hand side we've got outputs, so it's a three-way sequence that we can visually see our data flow through, so we can see what we've received into Airtable, we can see or take actions on that data in the middle, and then we can see exactly what that's returned in our outputs. But first, before we see the inputs and outputs, we actually need to connect to the system. So inside of every node, you'll have a series of tasks that you'll need to complete or a series of steps where it will ask you to choose a dropdown in order to select the most appropriate action. The first one is always going to be a credential to connect with, so right now we we do not have it connected to any Airtable that we have externally, so here might appear empty to you, and you're going to create a new credential here. Now these will be different app, but they have the same core concepts, and always n have some really useful documentation linked.

That you can go directly to the documentation for that specific node, I.E., Airtable, and see exactly where to access the different credentials. So, for Airtable, we need a personal access token, and we can get that by going to the personal access tokens page, opening that up, and clicking “create a new token.” It’s then going to give us this page, and we’re going to just, for example, call it “n test demo.”

Then, back in the credentials, it will tell us what Scopes we need to add to our token. The Scopes are just what access are we giving that token? Is that token able to read our records? Is it able to write to our Airtable? Is it able to delete records? All of these things we need to give it the right scope so that it’s able to perform the right actions on our behalf. So we’re going to add “data records,” “write data records,” “read,” and “schema bases read.” So we’ve added those three Scopes, and now we need to tell it what tables it’s able to access. So we’ve got to add a base here. So if you click “add a base” and scroll down, it will give us all the different options for connecting. You can see I have a lot of different bases here.

To do this, we need to have already set up a table. If you go to Airtable and set up a demo table, you can see I’ve set up a base here, “scrapes.doai.tutorials,” and then we’ve got two tables, “financial” and “demo data.” For now, we’re just going to use the “demo data” table, and we’re going to put “test name,” “random notes,” assign it to me, and it’s “in progress.”

So what we now need to do is connect this table to our access token, or connect our access token to this table. So if we go back to the Builder Hub, we go “add a base,” and we know it was called “scrapes.doai.tutorials,” that should now appear there once we create the token. We’ve then given it permission to access that table, and I’m going to copy that here by clicking here, and we’re going to go back to our workflow where we were setting up our Airtable token, and all we’re going to do is paste into our access token field. Critically, we’re going to rename this because you’ll have too many otherwise that are named “token 1,” “token 2,” “token 3,” and when you come to use them in the future, you won’t have any idea what platform they relate to. So we’ll give it a sensible name like “Airtable test API token,” and we’ll say that, and that should confirm then in green if it’s successfully connected to our software. There we go, “connection tested successfully,” perfect. We can leave from that.

So we come back to our Airtable canvas, and we’ve connected up our test workflow trigger to our Airtable node, and you can see that’s got a name, “Airtable.” Now, tip number five is about visually seeing the inputs, the Transformations, and the outputs. So what we’re going to do is we’re going to fill out in the middle here some options in order to pull our data. So right now we’re receiving no inputs because we’ve got the test workflow trigger, which is just pushing an empty set of data to our Airtable, but what that will enable this to do is run the Airtable node. So right now we’re searching for a record, and we’re going to search, but like I said, we can change any of the methods here, and they’ve all got a description underneath. So we want to search or list all of our records. We’re going to connect it to a base, and this is all Airtable-specific naming, and each node you connect to will have specific names for here, but Airtable uses “base.” So we’re going to connect to the list, and you can see that’s now given us access to that. Whereas if we had not filled out this correctly and given it the correct access, this would not appear in the list, and we’d have an error at this point. So now we know we can connect to the base successfully, we will choose the “demo data” table, and we’re not going to filter by anything, so we want to return all of our records, so we can test that step. And you can see on the right-hand side it’s now returned the records that we just put in the table. If you want to visually move these records, you’re able to click and drag and drop all of these different fields, and we can now see much clearer the outputs, which was the “test name,” “random,” “signy.” You’ll notice that this is in a strange format; this is adjacent format. And tip six is about managing all of the different data formats and understanding those properly.

Tip number six is interpreting table data, JSON data, and schema data, and figuring out the difference, and it’s actually really simple when you distill it to its principles. So to make this easy to understand, I’ve expanded the data set, and we’ve got now “name,” “task,” and “status,” and I’ve put in some demo data in our Airtable, and we’re going to pull that data using the test step, and you will see we have a full record of all 20 items in our JSON data table. You have this on the inputs as well, but because we’ve got no inputs at the moment, uh, we can’t format those. Table first is a really easy way to visualize your data; that’s how we conventionally see our data in a business. We normally see it in a spreadsheet table; each row is its own unique set, exactly like we see it in Airtable. So this is the way that a human would probably interpret it. The schema you can see just distills it to a single record, and the reason for that is the schema is just understanding our fields in the data rather than the data itself. So this tells us that we’ve got an ID field, a created Time Field, a name, a task, and a status field. The “a” next to it just symbolizes that it’s a certain data type; in this case, it’s just a string, which is just text. All of them are just text. You may notice that we didn’t have ID and created time in our initial fields; that’s because they’re hidden fields created by Airtable itself to help us manipulate those records, which we’ll come on to later, but it’s got the name, the task, and the status that we had before. So you can see the different fields there. Now, JSON, in contrast to our table, does not display things in rows, but instead we get the full set of columns within these curly braces, and that is identified as a unique JSON object. It effectively flattens our table into smaller level objects that we can then manipulate easily. So you can see we have an individual record relating to David Kim, his task “to optimize database queries,” and the status there, and that will be a record in the database here. JSON is really good for data inspection; we can see the full 20 items; we’ve got multiple pages here. Table data is for quick data scanning and spotting trends, so you can see easily that this is easier to interpret, and then schema we can use if we’re just looking for a certain field name; it’s much easier to read that off here than a complex JSON structure. So schema, we can just grab either the data type or the field name from here.

Now, for tip number seven, we’re talking about mastering static data and working with static data. So we’re going to connect a node up to the Airtable, and this is a node that you’re going to use so frequently, called a “set node,” “edit fields,” or “set.” It allows us to just pass data or extract certain pieces of data from our software or our business use case. So we’re going to open this “set node,” and you can see it opens up with this “edit fields” node. Again, we’ve got the inputs, the transformation we want to do, and the outputs; really simple data visualization. So it gives us the option to drag input fields here, but all we’re going to do actually is we can see the output from the Airtable have now become the inputs for our set node. We’re going to click in this box, and it gives us options on our fields that we want to pass through. So inside the name here, we’re just going to put “test name.” We’re going to give it a data type, so we’ve got the five different data types here. So we’ve got a string, that’s something like a text; we’ve got “number,” self-explanatory; we’ve got a Boolean, which is a true or a false; we then have some more complex structures which are like our JSON objects that we’re passing through; we have an array, which is in square brackets; and we have an object, which could be a JSON object like the one on the left-hand side. So for now, we’re just going to pass through a string, and we’re just going to say “hello world.” So at this point, we’re going to hit “test step” again; that’s going to run the previous nodes, pass through the data, and pass through new data, which we can see has passed through as “test name,” “hello.” Now you’re probably wondering at this point, why is it run 20 times? We just wanted to pass one “hello world” through, and it’s because by default all of the nodes in n8n operate on a per-input basis. We’ve given it 20 records from Airtable, and we’ve run it 20 times. If you want it to only execute once, you can go to settings, and you can hit “execute once.” We’ll test that step again, and it will just execute it for the first item only and will output “hello.” So we’re going to turn that back off and run that again, and you can see that we’ve received the “hello,” but we’ve not received any of the Airtable data that we wanted to pass through in transform. So there are two ways to do this: one is by including other input fields, and we tell it to include specific fields or all, so we can pass it through that way. But the whole point in using the set node or the edit fields node is that we actually just want to take two things through, the name and the task; we’re not interested right now in the status, so we just want to take those two fields only.

Now, tip number eight is where it starts to get really valuable if you’re a business. There’s not many times you’re going to be passing static data through like “Hello World.” You might have a fixed value like an API key that you’re passing through or something like that, but the majority of use cases is we want to use n8n because we want to transform our data or take it from one platform to another, and that often requires using dynamic data. So we’re going to remove this in the set node, “include other output fields,” we’re going to run it again, and it’s just going to come through with our 20 “hello worlds.” What we’re going to do is first look at how do we include dynamic data just by writing it. So we want to take the name and the task through to the next stage. So we’re going to copy those out, and we’re going to call the first field “name,” and that’s going to be a fixed field, and we’re expecting a string because it’s a name, and the value in here, what we want to do is say, “Okay, I want to pull every time for all these 20 records this name field.” There’s two ways to do that, but they both involve expressions. The simplest way to do that is to drag from the left-hand side in our inputs across here and drop it in the field, and you can see it pops up with a result here, which is for each of the records it gives us what the value would be, so it’s like an indicator of what that’s going to look like on the other side. The second way to do it is to reference by name, and it’s one and the same. So if we were going to do this from scratch, we would say “name” again, and the value in here we’d need to switch to expression. Then, every time we reference data in n8n, and this is just by default, we have to hit Shift and two curly brackets, and that will open up our expression. It prompts us immediately for all of the different values that we might want to reference. The most important for now for us is JSON, which as we saw before is the data that we’re passing from one node to the next. So if we click on JSON, and it’s “$json,” and that’s just referencing the entire object of the previous node, the Airtable output, to see that in greater detail, there’s this little button here. You can click on that, and on the left-hand side you’ve got our expression, JSON, and the right-hand side you’ve got the full object, the JSON object that we’re passing through. We can see that for each record here. So that just visually shows us exactly what we want to be passing through. Now you can see that this is the full object, and actually we just wanted to extract “name.” So the JavaScript for doing this is just a dot, and that enables to access an item within an object, and then we can get prompted with the different fields we can extract here, and in this case we wanted to grab “name,” so we’re just going to hit “name,” and you can now see we’ve got the result we wanted. Another way to reference this instead of using the dot is square brackets, and then single quotation marks around the field name. That is an alternative way to do it; they’re just different ways of referencing an item or a field within an object by JavaScript. So you just want to stick to one convention, and I eventually use dots. Now, dots are only good when the field name is a single word with no spaces. If it was “first name,” for example, and I’ll go back and can change the data object in second, then “.first name” with a space is not going to reference the correct value. I’ve gone back and changed the values to “full name,” so we’re just going to run that again, and what we’re trying to reference now you can see these have all failed because we’ve changed from “name” to “full name.” If I open that back up and try to reference the “full name,” it’s going to automatically, instead of the dot convention, use the second convention, which is the open square brackets, the single quotation marks around, and that successfully references. If I try to do the dot method, it’s not going to find it, and it’s going to show up “invalid syntax.” So just different naming ways to reference; I would always by convention make it a single word, either by connecting the name like this or putting an underscore in between, just because I prefer to use the dot notation. But with your business data sets, you don’t always get to decide that, and you can use the other method instead. But like I said, if you type out JSON, then hit the dot, it will still give you all of these different options, and if you click on the “full name,” then it will actually automatically pre-fill that for you. We can see on the right all of our results for those.

Tip nine is an extension on dynamic data, mastering dynamic data, and this I promise you is going to save you a ton of time when you’re creating workflows and having to go back and edit them. So we just passed through the data for the name, and we had “$json.full name” here. JSON only references the previous node, so often you’ll come in here, and you will add another node between those. So we’re going to open up the options here, going to add a second set node here, and we’re going to connect, delete connection, and connect that up to the set node, and we will just call this “middle” just to indicate it’s the middle step here. So now we are passing our data through a node between our Airtable and our edit fields node. So anytime we reference this JSON, we’re actually now referencing the previous node, which is no longer the Airtable, and it’s now the “middle.” So say, for example, we don’t pass any values through this, or actually we’ll pass just a test, we’ll call it “test test,” it will pass through 20 “tests” like we saw before, but now we want to access in this next field the full names from the Airtable. Now, because JSON only references the previous node, I.E., “middle,” we can’t actually access that from here. So how do we access that? There’s two ways again; there’s a drag-and-drop style, which is probably the easiest way to do it at first. So we can go to the schema view, and we can actually see all previous nodes. So in here, we want to grab “full name.” So inside our expression value here, we can just drag and drop our “full name,” and we’ll be able to break down the wording here and how to build those from scratch, but you can see that it’s pre-filled everything we had before, “json.full name” or “json[‘full name’],” and then it’s also appended this beforehand. But if we run that again, you can now see we are actually still retrieving the names as well as the data from the previous node. So that is the first way to do that. The second way is actually writing it again. So if we write in here “name,” how we do that is again we open our expression, we open the brackets, immediately tells us to reference the previous node using JSON, but we know we want to reference an earlier node here, so we scroll down, and we know we want to grab data from Airtable, so you hit Airtable, and it’s given us the object from Airtable. So now again we need to go inside the object by hitting dot, and then we will hit “item,” which just grabs an item inside the object, and then dot again to access the object or what value we want to grab from the object, and then it’s exactly the same before, “do json,” and then if we hit dot, it gives us all of the values inside the object. We hit “full name,” and well, we’ve got exactly the same as we had before. Knowing this is actually super critical; it might seem minimal, but you will go back, and you will edit a lot of your flows, and you will add nodes between nodes where you didn’t have them before, and it will cause a lot of headaches if you don’t name like this from the start, and you just use the JSON format; you will get these undefined errors all the time. So starting from scratch, I would recommend highly naming it like this, and it will save you a lot of time in the long run. You now nearly have all of the core fundamentals around handling data between nodes; you understand triggers, you understand what a node is, and you understand the inputs, the transformation, and the outputs. When you’re handling large data sets, thousands of records like you often do in a business, this next one’s going to come in really handy, and that is about pinning data.

So inside our Airtable node, you can see that we’ve got our inputs, our transformation, on our outputs, we’ve got the table data, the JSON data, and the schema data, and then we’ve got two fields over here. We’ve got this “edit field,” which is great for testing; you can go into “edit,” and you can edit any of these values. So we wanted to say this is “uh done,” and that will actually save it as “done,” so we can just quickly edit values rather than going back to our original data source if we just want to test something out. The second thing is “pinned data,” and it’s automatically pinned that because we’ve edited. So if we go back and we unpin, “pinned data” allows us, with thousands of rows, to save a lot of time when we’re testing. It also enables us to take values from our workflows that cause an error, and it allows us to rerun that through the flow. So you’ll often come up with errors, and actually you can go and push that data back into our test environment here. But for the sake of this, pinning data is just storing data in that node so that we can rerun on the same data. If you’re running thousands of rows of data, it’s not going to execute as quickly as it does now. So you can see it took a couple of seconds already with 20 records; with 4,000 records, it will take 10, 15, 20 seconds, and that adds up when you’re testing. So what you want to do is just come in here, “pin data,” so the node will always output this data instead of executing. So it’s basically like storing the data, and it has this little pin icon, and you’ll see how quickly this executes now, immediate, basically. So when you’ve got 4,000 rows or lots of data, which you will have with your business systems, pinning data is critical for testing.

Now we’re nearly at the end of the core concepts and the fundamentals of n8n, then we can get into the real nitty-gritty of building out workflows. Once you’ve understood these basics, the next one is important because at some point in time your nodes will fail. So the next one is about retries. So inside our Airtable node here, we’ll unpin the data, and we’ll go back, and we’ll execute that workflow again. So this executed successfully the first time, but this won’t always happen, in particular with AI agents or HTTP requests or services that are less reliable than Airtable. We’re going to want to implement some retry logic. So inside our settings here, we have a few different options. We have “always output data,” which we’re not going to worry about now; we have “execute once,” which we’ve covered already; and then we have “retry on fail.” This says if it’s active, it tries to execute again when it fails. So there’s no reason we wouldn’t turn this on because if we’re reaching out to Airtable and for some reason the server responds with something that means our data doesn’t come back, then this whole workflow is going to fail, and all of the execution that we worked for up until that point is not going to be worth anything. So if we click this on “retry and fail,” it gives us the option to change the max number of tries. So if it fails, it will try three times, and it will wait 1 second between tries. I normally just leave these as the default values. Sometimes if you’ve got rate limits or other things like that, you can stick it up to a higher weight between retries, and then you get the chance to say if an error does happen, do we want it to stop the workflow entirely? Well, in this case, if it can’t grab our Airtable data, then there’s no point in continuing, and we want to make sure that on the error it just stops our workflow and throws an error. We will cover later way more around error handling because it’s super critical for business implementation, and we’ll cover these different options. But the three different options are stopping the workflow completely, continuing and passing that error message as a regular output, or continue and passing that error message to a different branch. So say we wanted to record that error somewhere in a log, then we would use this last one here. If the Airtable wasn’t result wasn’t important, then we would use “continue” because the error would not stop the workflow from continuing. However, it’s critical to our workflow here because we’re trying to grab tasks and full names, so we actually just want to stop the workflow when that happens.

Tip 12 is the most overlooked part that I’ve seen in all templates on the n8n template library, on YouTube videos; this is so critical if you’re delivering client projects or you want your workflows to be maintainable, and that tip is naming consistency. So right now, if you were somebody in a business and you came to this workflow, would you be able to tell me what happens? So we’ve got “when clicking test workflow,” we’ve got “Airtable,” we’ve got “middle,” and “edit fields.” So from looking at this, I have absolutely no idea what this workflow is going to be doing. We’re going to cover this in way more detail later when we talk about client standards and consistency in this, but to start off with the basic fundamentals are naming your nodes, and the way you do that is you go into the node itself by double-clicking, and here we’ve got the edit icon here, and we can rename here. So it’s important to have consistency in naming so you can revisit workflows and you understand the logic of your workflows; makes it way more reusable. For me personally, I follow a convention that makes it easy to reference.

The node but also describes the action taking place, so all nodes will have the symbol of the software. So we've got the Airtable here; if we bring in Google Sheets, you'll see that it has a Google Sheets symbol here. So I don't necessarily feel the need to reference the service name within the node; however, you can if you wish. But the fundamental actions that you'll use with a service are getting data from the service (i.e., reading data like we did from Airtable), posting data to the service—and that is actually sending data to the service—updating (so that's partly posting, but actually we're checking if the record currently exists), and deleting (you could be removing data from that service). This is also the convention you use with API requests, which we'll touch on in the API Mastery section, but for now, just treat those as standards for naming nodes.

So instead of "Airtable" here, what we're actually doing—we're getting the task records—so we might call this "GetTaskRecords." And if we name that and come back out now, immediately it's so much more obvious to me, as an outsider looking at this, what I'm doing. I don't know exactly what the tasks are, but before it said "Airtable," now I know we're getting some sort of record from Airtable. I've put this in Pascal case here, which is where you have two names that are both uppercase next to each other. You could alternatively have spaces between them, so we just have normal case like this, or you could have camel case like this. It's entirely up to you what convention you use; I just use Pascal naming to make it easier to reference those previous nodes.

You might want to call out specific things like triggers with a separate naming convention. So instead of taking an action like "Get," "Post," "Update," and "Delete," you might want to call this a "Manual Trigger," and the way I do that is just calling it out with an underscore, so I have "Manual_Trigger." We then get task records, we then set values in the middle, and then again we're setting values, but it's not very descriptive because we're not actually taking many actions with those. But for this one, for example, we are getting the name, so we'll call it "GetNames." You can see now that's immediately more obvious. We've not got to the point of adding notes to the flow yet, which is entirely possible and recommended, but the starting point is making your nodes easy to look at and understand exactly what they're doing without having to go into every single one. It's fine when you have a workflow that's this small, but I'll show you an example now of where it's not going to be okay if you have that.

I've jumped into an example here of a template in our school community where we pass financial documents. Now you can immediately see I've used this name in convention on these nodes, and it's immediately obvious, even if you took away all of these notes—we'll just take those up there—it's immediately obvious on the outset what is happening. So we have some sort of Google Drive file trigger; we're then obtaining the file; we're extracting data from the file; we're formatting it in some sort of capacity; and then we're processing it one by one and using an AI node to extract data and update the financials into Airtable. So immediately, without any notes, I can see from the names of these that we are taking data from a file, we are extracting and formatting that data, and then we are uploading—loading—to Airtable. Your client will also think the same; if they have access to the nFlow, they will go in here, and they will be able to immediately understand at a high level what the workflow is about. Really, really important. That brings us to the end of the core concept section of the course. We'll now get started and dive deeper by building out practical business use cases using your data. So we're going to use an example of an invoice passer; we're going to build that and talk about the data fundamentals next.

So we're going to end up with something like this where we are monitoring a file source for our business, like a Google Drive store of all our documents. We're going to cover how we would process all of the different file types that we might use; we're going to see multiple inputs to our flows and multiple triggers and how we handle that; and we're even going to touch on how we set up our first, first AI agent and why we've set up a loop here to cover all incoming documents one at a time, why that's important, and then how to go and update our database in the back end to make sure that we're storing the correct information and validate that.

Before we start building out any workflows, a good first step is to understand and plan out the workflow that you're going to build, just so you understand the logic that you're going to follow throughout. You'll obviously make iterations as you go through, but it's a really good starting point, especially if you're working with clients, to plan out exactly what the flow would look like, make sure you're on the same page, and then move forward with the first version of the flow. So to do that, we're just going to use some sticky notes. So we're going to open the nodes panel again, and if you type in "sticky," then you'll get the sticky notes. A shortcut to get to this is actually just the Shift and S, and it will open up a sticky note. You can see that there's a few options on here; we can change colors, so I always just use white as a standard for informational notes, purple for supplementary, red for things that have to change, but it's entirely up to you; you can use whatever you want. This is written in markdown format, so if you double click into the note, the double hash just says that it's a heading, or a second heading; if you put one hash, it becomes an even bigger heading. So you can see that three hashes will be even smaller. So that's just some markdown for you, and all we're going to do is just plan out the steps that we think we're going to use in this template to make sure the logic flows correctly.

So if we're passing financial invoices, we know that we're going to need to get a file, and that's probably going to be our trigger. So we're either going to do that from G Drive or Gmail, and in this example, we probably pull it directly from Gmail to show you the example. So our first step is like, how do we retrieve the file, or how do we retrieve the email? The next step, we're probably going to have to do some pre-processing. So you'll see in a minute that there's loads of data that comes through in an email, and we want to strip out all of the irrelevant data because that makes it really easy to—and clean—to work with. So we're going to have this pre-processing node where we just do some data formatting. Once we've formatted that email or file, we're then going to want to extract key information from the email or file, so we'll just put "Key Info," and that might be the invoice name, the supplier name, the invoice number, the price—all of the information that we want to pull, we'll do in this stage. Once we've got the clean data, we'll then extract it—extract that key info—and we're probably going to use an LLM or an AI agent to pull that data because it's going to be able to interpret multiple different file formats and multiple different emails and pull consistent info from multiple emails. We're then probably going to want to put that into our database. So once the information is extracted, we want to output data into our database. So actually, you can see already that we've got the outline for this flow now; we can move on to actually building the first version. These steps may change, but it gives you a good idea visually of the different categories you'll need and therefore how to start building this out.

So for the first part of building out our invoice passer, we're going to come back to our workflow here, and we're going to remove everything that we currently have. So instead of having a manual trigger this time, we're actually going to be monitoring emails or a Google Drive folder. So what we're going to do is get rid of the manual trigger for now, and we're going to click the plus icon; we're going to open up—let's go type in "email"—and we've got Gmail here. Let's set up Gmail to show you how to set up the Gmail trigger, and you can see there's one trigger, which is "On Message Received." Every time a message comes in, we will be monitoring that. We've got—when we open this—a few different settings. We've got to connect to the correct credential; we've got the poll times, so we can monitor every minute, and there's no disadvantage to monitoring every minute given we are on the self-hosted plan for n8n, so it's—we get unlimited executions; it just takes up server time. And then we are monitoring for messages received, and then for now, we won't simplify the response, and we'll see what we pull in. If you hit "Test Event," that's going to pull in your last email. So right now, we are monitoring a Gmail from mine, and that's going to pull in my latest email received in that inbox. Now what you can see on the right-hand side is we are in the JSON format, but you can see a lot of different data. You can see inside the JSON, we've got all of this different information; we've got the ID; we've got what thread the email was part of; we've got all of these headers; we've got the HTML content, so the pure content of the email. You can see this is like an overwhelming amount, and even if we go to the tables format, you can see that we've got all this information, and even the text inside the email comes as this big block of text that's really hard to read. So what we're going to do now is understand how to strip out the bits we actually want and take that forward for processing.

So setting up Google credentials—they've recently changed this on n8n—so now you have to do a few more steps, but I'm going to run through how we do it for Gmail. It's exactly the same for Google Drive, Google Docs, Google Sheets, etc.; you just need to set it up once, and then for each node, and then you can connect your nodes. So we're going to go into the trigger here or the Gmail node, and we're going to go up to "Connect Credential" to connect with; we're going to set up a new credential, and you see it asks us for a few different things. So we've got the redirect URL here; we're connecting using the OAuth 2.0 method, which is just a standard that's used across the industry to connect to different accounts; it's effectively where you have the Google sign-in page that is an OAuth 2.0 client. We then have two values that we need to go and collect, which are the client ID and client secret, and then we can rename this as usual here, "Gmail Account Test"; we'll name it for now. So what you're going to do is you're going to go to Google—or sorry, console.cloud.google.com—and you're going to come into this window, and you will be able to see the navigation menu on your left-hand side; you'll be able to see "APIs and Services." We're going to go to "Enabled APIs and Services." If you've not previously set up a project, it will probably prompt you at this point to set up a project, but if you have set up a project before, it will just pull you into that project. You're then going to actively enable which APIs we want our project to be able to access. I've already got them enabled, but you're going to enable APIs and services; you'll type in things like "Google Drive," and we'll click on that, and instead of saying "Manage" here, it will say "Install" or something to that effect; you're going to click that to make sure it's installed. We'll do the same for every app we need, so we'll type in "Cal"—again, "Google Calendar API"—we'll install—again, install all of those. So then we've got Sheets; we've got, you know, all of that stuff; Mail—in this case, we're going to have to go to "Gmail API," and then install there. Great, that's the first step; they're all installed. We're going to go back to "APIs and Services." The next thing is setting up our credentials. So we've given it access to the relevant APIs; we now need to give it access to our account. So we're going to go up here, and we're going to click on "Create Credentials." If you've not done this before, your OAuth 2.0 client ID will probably be empty, so you're going to go to "Create Credentials," and "OAuth client ID." If this is the first time you're doing this, it might ask you to set up an account; just follow the steps through, and then it—once you set that up as an external web app account—you'll be able to come back to this part in the tutorial and set up this client ID. So we then have "Create OAuth client ID"; we're going to choose a web application because we're just connecting it to n8n; let's just call it "n8n Test Demo" here; you can call that anything you want. Now this is really important; we're going to need to input our authorized redirect URIs, and that just enables the server from Google Cloud to connect to our n8n nodes. So we're going to go back into our test workflow; you see this OAuth redirect URL; we're going to click to copy on the right-hand side; to go back, we're going to add that as an authorized redirect URI there, and we're going to create—that's going to appear then with our client ID and client secret, which are the values we need to take back to our environment. So we're going to copy that, go back, paste them in here—whoops—so we'll take the client secret; we'll go back, and then it's going to prompt us to sign in with Google, which we're going to need to do to just validate that. So I'm going to sign in with the account that I'm on at the moment; click "Advanced," and then go to "also doapp"—this might say something like "render" or whatever your service is hosted on—but we're going to go to it; it's then going to ask us to confirm the access and the permissions. Brilliant, connection successful. If we go close that window, we'll go back to here. We now can close that, and we're all connected to our account. We fetch the test event; you'll see we're pulling in an email from that account. So we're just going to pull that trigger up to our planning so that we have it in our first planning stage, and we're going to go into the trigger, and we're going to pull the latest email, and I've just sent an email to myself with an invoice so that we can process something that's actually useful. And you can see inside the email we have a bunch of formatting which will show up as HTML code in our email, which makes it really hard to read, and then we have important information that we're going to pull from the invoice, like the price, the provider—11 Labs here—different invoice numbers and line items, which we can all break out in our data when we process it. So we've got the node open here for the Gmail trigger, and we're pulling that email directly through. So I'm just going to use what we used before and pin the data so that our data doesn't change and so we can test with consistent data. And you can see on the right-hand side we've got the output in a table format, but you can see that this email contains a lot of supplementary information that's going to make it hard to process for both us as a human and for the LLM later on. So what we actually really want to pull is just the text from the email and any key things like the subject, which might give us some references to what it is, who it's from—all of the key information like IDs, thread IDs—but there's a lot of supplementary information that we're not interested at all in here. So I'm going to show you how to strip that out now.

So we're going to open up and click the plus icon here; we're going to use our trusty "Set" node or "Edit Fields" node, and we're basically just going to cherry-pick the fields that we want to pull through. So one of them that's immediately becoming obvious is like we should probably have who it's from, so it's going to autofill that, and we're just going to have "From," and instead of naming it "Json," we're going to use our rules around proper, and we're going to call it "GmailTrigger.item.json.headers.from," and you can see now it's pulling that email. We're going to also pull the subject, so we'll drag and drop the subject and do exactly the same there. Then, in case who wants to reply to the email in the future, we're going to need the IDs and the thread IDs, so we're going to pull those across as well. Yeah, I haven't asked any. Then we're going to pull the text as HTML, and you can see that's a load of code here and not the actual text in the email, but it will contain the text in the email. And the reason I'm pulling it text as HTML is that I can show you in the next stage that if you don't have something that already strips out the HTML, there is a way to do that by yourself. And we'll also just pull the text, and we'll update these nodes so that they will reference the naming so that if we add any nodes between them, then will be easy to—they will continue to reference the correct node, and we can always come back in the future and put another value in here, but for now, all we want to pull from this great amount of information—these things—and focus on those things. That's why the "Set" node is really powerful for doing that—can strip out just the things you want to look at—and then we'll just call it "SetEmailValues" to correspond with our naming. So once we have that, we have—then if we test step—pulled just the values we want, and we now have a much cleaner format of data to work with than the previous one. So we have the values as HTML, and I'm just going to quickly cover what HTML and markdown is. So we've got a page open here from dev.to, and it visually shows you what markdown looks like. So we've got a list of headings here, and like we said before, the hash represents different heading sizes, so your first headings will be single hash, second headings double, etc. You then have these bullets or dashes to do your list items, and then there's other syntax like double star for bold text, single star for italic text. Now that is really easy to read and a really useful format for both us, but also a really good format to pass it into an LLM later down the line. And then we have the foundation of web development which conventionally uses HTML. So if you open up the console for a given web page, you'll see that there's lots of these different HTML tags like "head," etc., like this—had—these are XML tags that open and close, so we've got "head," and then the close of the header; within that, we've got "page title." Now when this is written in HTML, it's much harder to understand and looks like this text here—long, very confusing—all of these different tags here that are hard to read, whereas when is it—when it is written as text—much easier to read; it's still got these characters in which represent new lines, but actually we can much more quickly identify the actual useful information from the text here. So the way we can do that in n8n is actually if we open up our tabs here; we've actually got a "Convert Between Markdown and HTML" node, and all we're going to do is just inside the node have "HTML to Markdown," and we're going to drag and drop the "text as HTML," and you'll see it will actually give us the same text as we've got here. And this is just to show you that if you've ever dealing with HTML formats, you can convert it directly using this node rather than relying on the Google node to convert for you. And if we scroll down to the results, you can see that we've received the data here as a much more readable—stripped out the HTML—set of values. So we can see actually the content of the email there, and that's how we're going to pass it into the LLM later on.

So we've processed that data, and it's now in a much more readable format. We're now going to move these steps across and actually just check that we are outputting the correct data, and this is going to conclude your first automation completely from start to finish, and we're going to take in an email; we're going to clean the values; and then we're going to output it to Airtable. Now to show you how easy that was to make your first automation. So we're going to connect a node here, and we're going to type in "Airtable"; going to open up that node, and what we want to do is just create a record. So for each email we're processing here, we just want to create a new record. We're going to go back to—we can see the data that we're receiving in; we've got our credential already set up earlier, and what we're doing is creating a new record, so we're going to choose our tutorials base that we set up earlier, and now we're going to go back to Airtable to set up an appropriate table that contains all of these columns: "From," "Subject," "ID," etc. So we're going to come back into our Airtable and create a new table, but when we click plus here, there's a quicker way to do it. So if we hit the "23 more sources," and we go down, we've got "Paste Table Data" here, and now we're going to type in the values that we are—we need for our column, so we have "Thread ID," "From," "Subject," "Text as HTML," and I think we had "Text," which was stripping out the HTML there. So we're just going to go "Auto Detect Delimiter," and it's going to appear underneath that we've got these different field headers, and we're going to "Import Pasted Data," and you can also—and then it's going to ask us where we want to import it; we want to do it to a new table; it's going to treat them all as long text fields, and we can actually change the data types up here. So "Thread ID" is probably going to be a string; "Subject," again, single-line text; "Text as HTML" is going to be a long text, and that's also going to be long text. So we're going to import those, and that will create the table quickly for us. Now we've got all of the different values that we need; we're going to go back to our workflow, and we're going to hit "Refresh List" up here, and that should now appear as an imported table. I forgot to rename it, so we'll come back here, and we will rename that to "Emails," and then we'll go back to our workflow, refresh the list, and we will go to our "Emails" table. So there's two options here: we can map the columns from our data to our Airtable manually, and this is what you normally do because you don't always have the same name in convention from your data sources to your other data tables, or if they—if you know the columns match exactly—you can just map them automatically. So "From," we'll search for "From"—exactly the same case, so both lowercase—in our Airtable, and if it finds it, it will create that, or it will add the value to that, but you're mostly going to use map—each column manually. So we're going to do it manually here, and again, it's as simple as dragging and dropping from these over here to the correct field. So we've got "Subject" in there; we'll grab "Thread ID" and put it in there, "Text as HTML," and "Text." We're then going to rename the node to "PostRecords"—or "PostEmails"—and that just tells me that we are pushing our emails to the Airtable database. We'll then give that a run and see if that's successful. Okay, so it's come up as successful, and it tells us in our output the fields that have been added to our Airtable. So if we go back to the Airtable…

We can now see that we have added all of those fields directly to our Airtable, including the full text of the email. So immediately we can see all of the information from that email. But you can see it's in a pretty poor format. But that is your first automation, getting from an email directly to pasting that in Airtable. Well done on getting to this point; like the first one is always the hardest, and you've done a really good job if you stuck to it to this point.

We're now going to expand on this, figure out how to format and process the data, and actually get it to something usable for your business, to pass invoices, whilst also learning all of the steps it takes to be a master at n8n fundamentals. So we'll come back to our workflow, and again, we've completed a really cool first automation here. So we are taking an email from our Gmail that we've connected up; we are extracting only the values we want and need from the email using the Set node, then stripping out all the complex HTML formatting, and then we are posting that to our Airtable so that we have a record of every single—or we could have a record of every single email that comes in.

To activate that workflow and actually have it run continuously, we'd hit activate up here, and this might give you a warning the first time to say that this will run continuously. But what that means is now every single minute an email comes in, that it will be processed through this step, and those will all appear in the executions log that we mentioned earlier. So you can see all of the successful test executions we've done; all of the production executions will also appear in this log, so you can see the historic runs of that. However, the thing that we did not do there is cover how to handle different file formats. So in the Gmail trigger here, we've actually—if we fetch the test event again—we're actually pulling just text values from the email, and we're not pulling the attachments which were PDFs attached to the initial email. That's what we'll cover now.

To resume our flow, what we're going to do is just copy and paste everything we had below, so that we've got our initial automation still saved, and then below we've got a new automation which we'll start working on. We'll delete these out by highlighting them and delete, but to stop any tests from running on the top flow where we're already done with testing, what we're going to do is just click onto this and hit deactivate, or "D" on your keyboard, to deactivate each of these, or we can highlight the whole lot and deactivate or reactivate with the—. So we're just doing that so that we can focus on testing our next flow, where we're actually going to deal with multiple data formats.

So we're going to get rid of our Convert to Markdown because we just did that as an example; we're also going to unattach our Post Emails, and we're going to put that later on in the stage because we're still going to need to post to Airtable later, so we can reuse that node. You'll notice now I've copied and pasted; we've got "1s" appearing by each of the node names. That's because no node name in n8n can be exactly the same as another. So if we want to make this look cleaner, then we'll give it a more specific naming convention. So this would be—now we're looking at files, not emails—perhaps we'd say Set Binary Values or Set File Values, and you can see the "1s" disappeared there.

To get the file from our email, we need to go into the settings of the message received; we need to go down to the options, and you can see this Download Attachments; we need to switch that on, and we will fetch a new test event. It's going to warn us about unpinning the data and that it's going to override our pinned data; that's fine, we'll do that for now. So we've now pulled our attachment data inside this Gmail trigger, and immediately you can see we've got a new data type which is binary, and we've got some sort of attachments here: Attachment 0 and Attachment 1, and the options to view and download them. So let's download one and have a look.

So we've opened up that attachment, and you can see it's an invoice addressed to me, and it's got a lots of different details about the invoice; it was issued on February the 2nd; here's the invoice number; there's a total; there's a link to pay; all of these line items here, we're going to be able to, by the end, extract and put into an Airtable base so that we can reconcile our invoices just automatically from our flow. So we'll go back to the flow, and that was Attachment 0; Attachment 1 is just another version; it's just a receipt version of that same attachment. But going back to the different formats, you can see we've got a new format. So we had the table, the JSON, and the schema; all of those still exist, but we've also got the attachments which appear as binary files.

If you're not familiar with the term binary, binary is how computers interpret data. So this file would be made up of millions of ones and zeros which the computers then able to read and translate into something that's readable for us. So a binary file—so all attachments and file formats that we have that aren't text will be binary; that includes your docx files, XML files, text files, sheets, Google Sheets, all of PDFs, all of those will appear in the binary section of the format, and n8n is able to download that file, and then we're able to use the data inside that file to get what we need.

To make sense of the text within the binary file, we need to convert that from binary to a format that we recognize, like text or JSON. We're going to open up the nodes here, and naturally we're going to go to the Data Transformation; we're going to scroll down, and on the—there's a Convert Data section which is all about converting files from one format to another, and we can see this Extract from File says Convert Binary Data to JSON. So it gives us all of these different options in here, and we know that we're extracting from a PDF here, and we're extracting values from a PDF in order to turn them into text so that we can process them into our Airtable. So this node will open up, and again you can switch file types in this operation here, and the input binary field will always be called Data by default, so we'll leave it as is; we'll drag this node down here; we'll connect it up to our flow; and what we're going to do now is run our test.

So we'll come out to the canvas and hit Run Test Workflow. So we've come across our first error—problem in node Extract from File: This operation expects the node's input data to contain a binary file, but none was found. So what I'm reading from this—and you can see it inside the node itself—is that the previous output of this does not—it expected a binary file to be able to convert, but no binary file was found. Make sure that the previous node, i.e., the Set File Values, outputs a binary file. So basically the error is saying there's no binary file in what you've passed to me, and that's because in our Set File Values we're just passing text; we're not actually grabbing the binary file.

So if we wanted to grab the binary file, there are two ways to do this. Let's disconnect it here; we could connect it directly to the binary file that's from the Gmail trigger, and we could run that, and that would now successfully run. And we'll come back here, and we will run again, and you'll see that we've got another error, and the reason for that is what I just said was actually incorrect; they do not always call it Data by default; it's sometimes—especially if it's coming from a Gmail trigger—called Attachment. So what we're going to have to do is either put an Attachment prefix here called Data or go into our Extract from File and specify that we actually want Attachment 1 of the attachments. So for some reason, when we put in Attachment 1, it's going to give us Attachment 0, and Attachment 0 is Attachment 1; I'm not sure as to why, but the fields are just lined up that way in n8n. But we know we want to just process Attachment 0, so I'm going to put in Attachment 1, and you'll see from the output that that's going to give us Attachment 0. Normally, most of the time you'll be dealing with one file at a time, so it would usually be from a Google Drive, in which case it would be called just Data, and it most of the time is just Data. But when you're pulling from the Gmail trigger, it's important to know that we can update this binary field name, and it's just going to be whatever's up here. So we can see Attachment 0 has been passed through.

Now here comes the importance in naming—referencing the node names correctly. So inside Set Value—Set File Values—we made sure to reference all of these names correctly, which now means we can actually put this node between them, and Set File Values will still continue to work, whereas previously we would have had JSON., which then would have errored and not found any of the values from our text. So we've now got the text values from our original email as well as the file values. If we click in the Extract from File, you can see our output is the binary file, but also it's actually translated that like we wanted into text. So we've got all of the text from the actual invoice attachment of the email, not just the email itself.

Now if we consider our table again, we saw how unstructured all of the data was within the text that we read. So we got rid of the HTML formatting, but still there's unnecessary spaces everywhere; it's really hard to read, and we don't want to pass those—firstly, we don't want to look at those in our Airtable because that's really hard to read. So we want to strip those extra unnecessary characters out, and the second thing is when we pass it into an LLM, we are paying per character or per token that we send into the LLM, so we want to reduce our cost there. So what we need to do in n8n is strip out all of that unnecessary formatting to make it really easy for us and the large language model, or AI, or ChatGPT node to do that.

Now there are inbuilt ways in n8n to do that. If we go into our Set File Values node, we go to the end here where we've got text, and we hit "." inside the object, then it gives us some suggestions on how to edit this. So we can concatenate it with multiple things, but we don't want to do that; we can remove our markdown values, so if it's markdown, then we might be able to just remove all of the markdown formatting; we can remove tags, so this is another way to remove the HTML or some of the HTML; then we've got things like Replace where we can replace certain words or certain key values with things; there's a whole bunch of things that allow you to add, edit, like trim the end, trim all spaces, etc. But what we want is a catch-all to remove all of the unnecessary formatting that's made it through here. So you're not going to be able to do that easily within these functions or within these additional options that we can put directly in the expression. So what that's going to require is a separate Code node. If we go into the plus icon here and we go into—into the Core—there's a Code node in here, and you'll see that this is some JSON formatting. So again, we've got our inputs on the left, which are all our values; we've got the Code node in the middle, and on the right we've got our output.

For anyone that's not done any code, don't be alarmed; this isn't as difficult as it looks, and we're going to use uh ChatGPT or Claude to help us create these nodes for us, and I'll show you exactly step-by-step how you do that; it's really simple. So first let's go over this; we've got a Mode, and by default it runs once for all inputs; we're only considering one input here, so that's fine anyway, um, or we can run once for each item, and then we can choose JavaScript or Python; I just choose JavaScript because that's the stable version here, and you can see it says Loop over item input items and add a new field called my new field to the JSON of each one. So it's saying we're taking this JSON from our input and taking an action on it. So if you've not done any code before, all this is saying is for each item within our input, which we've referenced by calling the dollar sign input.all, take this action, and that is it. We're then saying, okay, at the end, return everything you've got. So if we run this, it's going to return what we—we currently have plus a new field called my new field. So you can see everything we've currently got, and then we've got my new field is equal to one, exactly what we've asked it to do. So I would not worry about manipulating this directly; I'd worry about the business logic behind what you want to do.

So we said before that we want to take the text that we've received and strip out all of these \n, which are new lines, new spaces, and all of the unnecessary formatting here. So what we're going to need to do to do that is understand a concept called regex, and I've asked Claude to explain it simply because actually it's quite a—a unique concept. So we have an example with a phone number here, and you can see it's got some parentheses and an exclamation mark; however, we just want to strip out the numbers. So it's given us some code here—here that actually gives us just the stripped out numbers; it's saying, okay, to clean the phone number, we're going to pass in the phone number, and we're going to apply this manipulation on it or this regex formula, and this pattern means match anything that's not 0 to 9 or not a digit and replace it with nothing. So that's where we've got this—some common patterns for stripping out characters are removing all the spaces, removing all punctuation entirely; we may not want to do that because we're dealing with numbers, and if we remove all the full stops, for example, then we will remove—we will change the number—the value of certain numbers; and then lastly you have more of a catch-all, which is remove everything except letters and numbers. The point in this is there are certain terms or phrases that you can use inside regex that will strip out exactly what you don't want; you don't have to go Googling all those; there's a really simple way to do this.

And to do that, we'll just come back to here; we'll copy and paste the example that's given every time; we'll come into Claude again; we'll paste that; and at the top we will—or ChatGPT if you prefer—this is just the simple way to do it: Create an n8n Code node in the below format that takes in text with unwanted characters and strips out new lines and all formatting except commas and full stops, and it's asking it to do it in this format, so it will return it in the n8n structure. If you're referencing a certain field, and in this one we're referencing text, we should also mention that the field input is called text. That's going to return us probably a 95% version that we might need to modify slightly, but you don't need to know the code to do all this; this—so it's returned the JavaScript function which we can just copy from there, and it says, okay, this will replace all new lines with a single space, remove all special characters except commas and periods, convert multiple spaces into a single space. If it doesn't work the first time, just bring the new code back into Claude and reprompt it or re-ask it for what's missing, and that you will get there eventually; it's a very simple, quick way to create Code nodes without having to write them from scratch. This is JavaScript code, so it is fairly readable by looking at it. Again, we're taking items from all the inputs, and we've got what it's called Dirty Text, which is the referencing our text field there; good job we told it about what text—what the input was, and then it's saying, okay, take the dirty text, replace the new lines with a space; so this is the regex here; replace it with a space; remove everything except words, spaces, comma, periods. So you can actually find this regex expression online if you want to make this yourself, but instead Claude just came up with that really quickly for us. So we're going to run that, and it's going to output a cleaned version in Clean Text. If we scroll all the way down to the bottom, we've got Text, and now our Text output you can see has none of the formatting that we have on the left-hand side; it's stripped out—out all of the things that we asked it to, really simply. This again is not 100% human-readable; it's still got some invoice links, etc., but it's a lot more readable than the left-hand side, and it reduces our token usage when we pass it to the AI node.

Finally, on the Code node, we will just rename it to what it's actually doing, so we'll call it Format Text, and we will save it there. The next top tip is around using condition instructions. So what we mean by that is we may want to process the file—the binary files—in one way, or any emails that don't have binary files, i.e., just text emails, in another way. So how can we get it to route those based on the inputs to take different actions on either? So what we're going to do is come up and add a node in here, and we want the Flow category, and the If. So we've got a few different ways to do this; we could filter out conditions, so if we're only looking for files—that emails that have files in them—then we could filter out the ones that don't. However, if we want both emails but we want them to take different actions, we can either use the If node or the Switch node. So for this example, we're going to use the If node, and it opens up with these conditions. So let's wire it up, and let's wire it directly to our Gmail trigger. You can see at this point that we can have multiple routes directly from one node, and n8n will process those sequentially from top to bottom. So if I put the If node first up here and I run that, it will actually run that If node first, and then the nodes down here. So processes top to bottom and left to right. So processes that If node first. Once that's run, it will then run the second branch. If I put that If node down below, it will run the first branch that's above it and then the second branch. You can see the top run and then the second run, and again, left to right will always run first. So we—so in this case we actually want to process them differently, so we will consider if the Gmail trigger has an attachment, then we will take Route 1; if it doesn't, then we will take Route 2 and process it differently.

So in—inside the If node, we can see the inputs on the left-hand side as usual, the conditions in the middle, or the Transformations, and then the outputs. So at the moment we've got no conditions. So what we're looking for is does the input—the Gmail trigger—contain an attachment? So on the conditions here, we've got a few different options; we've got names that we can refer to from our JSON data. So for example, again, we can pull in—if we scroll down—so we want to exclude all emails from a certain address, we just drag and drop the From Address into the top, and we say whenever the From Address is equal to, and then we can fix this to any email, then that condition is going to be true, and it's going to pass in the true branch whenever it's not equal to; it's going to be false. So if an email comes in from that email address, it's going to go to the true branch and be processed down this path, which we can connect to any node, or if it's not, it can be connected to another node. So here we just put Is it from example@email.com, and it's going to go down the false route, and you can see it's gone down the false route because actually it was from Simon at—. So what we need to do now is just identify the condition that is having a binary file attached to it or not. So inside here we just stuck with a default which was string, so we're comparing string values here in the From Address and the From Email, but actually when we consider a binary object, it is in fact an object type. So we're saying does that binary object exist, and we can just reference the binary value directly, and we can do that by putting the expression brackets, and we will say Gmail Trigger.item, and if we hit "." again, it will give us the example of uh JSON or binary, and you can see that's lit up green to suggest it does exist. If File Exists, we'll call that, then go through the true branch. So you can see it's now gone through the true branch because actually there are files existing with this email. So what we might say is if the file does exist, then okay, we're going to follow this route, which is Extract from File, etc. However, if an email comes in where it does not exist, then we're just going to process directly the text from the email. And what we're saying here is actually take one route if a file exists, take another route if it doesn't. So if a file exists, we're going to extract the data from the file and format that; if the file does not exist in the input, then we're going to follow this false branch.

At this point, you can see that we've now connected two nodes up to a single node, and you're probably wondering if this is possible at all—how will the Format Text react? So in this case, we're only ever going to have one input going into it, so it's either going to follow the true branch for—if it does have attachments—and go into the Format Text, or it's going to—follow the false branch—set the file values from the email and then go into the Format Text. One thing I didn't mention was the If node will pass through all of the data from the input, so we know that if we're referencing it from the previous node, it will be exactly the same. So yes, this can work, and it's only going to be processed one at a time. The only way it can work though is if this node receiving both inputs is handling them exactly the same, i.e., they're named to the same. So we can see in the Set File Values we are outputting Text, and from the Extract from File, if we just run it again, it's also in the JSON data outputting a field called Text. So the inputs to Format Text are always going to be called Text, and if you remember in the Format Text Code node we said reference the node name—reference the field name Text. So it doesn't matter whether it comes in from this branch or this branch; it will be processed; we'll never be going down both branches at once and have the trouble of receiving two inputs at once. So we know that a node can handle multiple inputs as long as it has the same reference from the previous value, like Text in here. However, what if we do have two inputs and we want to process both those at once? So say this If node didn't exist, and we'll just get rid of all the connections here and say the Gmail trigger actually when it triggered followed both paths: One path we were extracting the data from a file if it existed, and another we were setting the file values, i.e., just pulling the text—how does that work because now we're processing two lots at once? So this works correctly for our—for the same reason because actually we've called it both Text, and actually in this case it's output two items, which we can see in the runs here: Run 1 is the binary file, but—

Also, has our stripped out from the binary file and run two has run through it, which is just the text from the email. So we're actually able to get both here. However, if this format text required both inputs to be completed before it runs, then what we'd have to do is introduce the merge node.

If we go across here and we have, we go to flow again; we've got merge. So if we drag over the merge node and delete these connections, the merge node will effectively allow us to combine or repend or manipulate our two inputs. We can add more inputs inside here, up to 10, and the option it gives us here is to append them. So if we run that, we'll have one after the other. So it'll effectively be two sets of table data in two different rows.

If we combine them, we can choose a field to combine by. So we might want to match up two sets of data; we'd use the merge node for that. And we can write the field names in here, and if they have different names, mark that. The outputs from that we get to choose; we could have both inputs merged together, so all the data in one row, or we could have um, just the data from one. We just want to pull the input data from one. We don't have to just combine by matching fields; we could combine by position. So if we've got two inputs and there's only one initial email, then actually it might make sense to just combine by position. And what that would do is just combine all of our fields together, but in this case, it would combine all of our matching fields together, so Tech TT. But in this case, if we combined by position because we've got a field called text in our file input and a field called text in our email text input, we'd probably lose some of that data. If we combined it by position, it would just have one text output.

If you wanted to get more complex with it, you could run an SQL query to do the merge, but most of the time, 99% of the time, you don't need that. Append and combine will work. There is one final option, which is choosing a branch, and this allows us to just wait for both branches. So sometimes we want two branches like this to both complete before we pass through the item, and therefore we'll just use this merge node to actually take both of the inputs and wait for all inputs to arrive and then just output everything. And it's just an easy way to wait for all data to execute before we pass through. But in this case, we don't actually need the merge node because our format text handles it directly. So we're going to delete that out; we're going to reconnect those up here.

So every time we run this automation, we are going to be flooding the server memory and actually adding more and more data to that memory. You can think of it like your brain; you can only hold so much in your memory before you get overloaded and you can no longer do any tasks. The same counts for our server. If you are hosting on n8n Cloud directly through n8n, then you probably have a significant amount of memory. If you are self-hosting, you've chosen the amount of memory that you want to use. And if you are handling thousands of rows and you keep running these test workflows, they will continuously be appended to the memory and stored more and more and more until you come upon an error where it tells you you you have no memory or not enough memory to perform the action. A simple tip to prevent this is actually between the test workflows; you can go down to the bin icon and click that, and that will delete the current execution data and remove it from your memory. Super simple tip, but actually will save you when you come across that error.

Now, one of the most powerful features of n8n is that it can handle multiple inputs at any one time. So we are pulling here our emails every single minute, and some of you, if you have a lot of emails coming in, would actually be processing more than one per minute. Sometimes, say some two emails came in in in one minute, then they would also be pushed through this flow at the same time. Now, sometimes that's okay with some flows, but ones where we are processing heavy amounts of data, we might want to spread out those so that we're only processing one file at a time, getting that through the loop, getting it done, and then processing the next. And that's why loops are a really powerful feature of n8n, one that you'll end up using a lot.

So we'll open the nodes panel here, and in the flow, we've got this Loop over items in brackets, split in batches, because that's what it used to be called. We're going to click that node open here, and you can see we can choose the batch size in here. So we're just going to choose a batch size of one, and it's the loop over items node. You can see sometimes that when you connect in the middle, if you've clicked a previous node and then you connect a node in the middle of the workflow, it will just throw it on top and connect it to a bunch of different things. So I'm just going to cancel that, click somewhere random on the canvas, type in loop again, and bring that over here, so it's disconnected. You can see that Loop comes as a two-node piece, and the reason for that is it's almost like a demo of the mini loop that you need to take. So we've got the loop over items node here; we've got the loop, which is you need to replace this with the nodes that you want to loop over, and then after the final node that you want to loop over, we return it back to the loop to process the second one or the third one or the fourth one. So it's just going to process them one at a time.

So the easy way to do this is to delete that node, delete that line, and now we have the loop items, and we're just going to disconnect these, and we'll just consider this flow where we've got a file only, and we're going to connect that there, put that in the middle. So now the process that we want to do is actually data format on that individual one, format the text, and then output to our Airtable. So we're going to attach those all together and loop it back around. So now for every minute, if a m if multiple emails come in here, we got two emails, then we will only follow this, then we will follow this loop per each email rather than two emails going into here and extracting the files, two in here, two and here; it will just separate them into individuals, which will prevent any problems. This only is important where you want to process them individually. So because we're going to include an LLM node that processes the input, we want to just do it for that specific email and just handle them separately. So we're going to add that loop there; I'm just going to disconnect so that we can run the next part of the flow, but we essentially got to the point where we'd extract from a file, format the text; we are nearly there with creating a full invoice extraction and processing workflow. We've got one key stage next, which is how do we extract the info, and for that, we're going to use the AI nodes.

So if we come into the nodes and we go to Advanced AI, we're first going to run over what each of these mean. So AI agents, you've probably heard a load of different definitions of AI agent, and you're thinking, what the hell is an AI agent, and how is that different from things like ChatGPT, AI workflows, AI nodes? There's so many different terms, and here I'm going to distill the exact differences between all of those terms so that by the end of this module you'll be really clear on exactly what an AI agent is, what an LLM is, what are the advantages for your business of using an AI agent versus an LLM, and what are some good business use cases that we could use an AI agent for versus a non-AI agent for the various areas of your business: customer support, sales operations, document processing; we're going to cover it all.

So we're going to start off with what an AI agent is not, because that probably makes it clearer given what you already know. So you'll be you'll probably be familiar with ChatGPT. ChatGPT is just a layer on top of a large language model, or what we call an LLM. It takes our queries as inputs, and it produces outputs. So we type on message in, and it gives us an output. And the way that works is a large language model is trained on billions of parameters and lots and lots of data. It works by predicting the next most likely word in a sequence. So we ask it a question; it then uses its training data to provide an answer of the most likely words in that next sequence.

So the next concept we're going to cover is really really important in distinguishing between an LLM and something like an AI agent. So we're going to cover agentic and non-agentic workflows, and once you understand this concept, you'll understand that AI agents always fall within agentic workflows, but you can also have agentic workflows that don't have AI AG inside them. So a non-agentic workflow is like prompting ChatGPT or typing a query into ChatGPT, and we call this zero-shot prompting or non-agentic workflows. Something like, please type out an essay on topic X from start to finish in one go without using backspace. So we are prompting the large language model, and it's giving us a response based on its training data. An agentic workflow breaks down that task into multiple subtasks and makes decisions based on the data, but also decisions based on the research that it conducts. So an example of it breaking down subtasks here might be write an essay on electric cars, and then it's asking itself, okay, do we need any web research to support that? And perhaps it's going out and actually grabbing that research from a tool that's connected to it. Then it's writing the first draft based on on that research, and then it's in the next step considering what part needs revision or more editing and actually then telling itself, okay, these are the bits we need to edit, and editing itself. So instead of this single, linear flow from start to finish, the agentic workflow breaks down the different subtasks and actually thinks and revises based on the information and feedback that it's provided back to itself. And this can be inside one singular AI agent that's giving itself steps and planning out a task, or it could be multiple LLMs chained together in order to create a sequence of feedback or a sequence of decisions. The important part here is that while both of these use AI or can use AI, the agentic workflow exhibits agency, I.E., becomes agentic through its ability to make decisions and adapt its strategy based on the content it encounters rather than following a fixed processing path. So it's able to make decisions dynamically based on the inputs and take dynamic paths based on that information. That will all become really clear in the next few examples.

We're now going to cover a business example. If we were building out a workflow, what would it look like side by side if it was agentic versus non-agentic? So we're going to going to use an example where we're building out an invoice passer. So we're receiving in an email with an attachment of an invoice, and actually we're processing that invoice and extracting the key information like supplier details, total price, invoice number, and various details based on that attachment. That attachment can come in any format, so it could be a PDF, it could be an XML, could be a docx, it could be the text inside the email. We have two flows here which represent how that could be done in a non-agentic way and on the right-hand side how that could be done in an agentic way.

So on the left-hand side, we have a single linear flow that takes our email, an AI node or LLM extracts all of the information from that template, and we are looking for template matches, I.E., supplier number in invoice number, VAT references; it's going to extract all the information that it can from that text, and then it's either going to take a linear path of, okay, was it a success? Yes, we'll add it to our database; was it a success? No, then we will flag an error, but no further action is taken from this; it's from start to finish non-agentic because it's not making any decisions; it follows a simple linear path from the email receipt to story storage or error handling. There's a single LLM extraction attempt, so it doesn't matter what type of content has come in; if this is only built for PDFs or only built for text, then it's just going to try and extract based on the information we've given it, and it's not going to adapt its approach; it's just going to be a one-size-fits-all approach, try and pull the text from the PDF, but if it doesn't have the functionality to do that, then it's going to fail. We then have a binary success failure option, so we have no option there to retry the process, and then it's going to try and match a fixed template regardless of what format the invoice comes comes back in. So in summary, it makes it non-agent it because there are no decisions or adaptation in the flow; there's no feedback loop where it's iterating on its own understanding; it can be connected to tools, but no decision is made based on the input of what tools to use. And this example we've not connected it to any tools, and then there is a fixed output every time, same output.

This contrasts to the agentic invoice passer, which you can see when we go through makes decisions and provides feedback to itself. So we receive the email in; we're then classifying the content, I.E., understanding what data format is it in? Has it come in as a PDF? Has it come in as text? Has it come in as an XML file? We're then passing it to the AI or LLM node here, and this could also be an AI agent; we'll come on to the specifics of what makes it an AI agent, and then based on the content it's received, it's then taking a decision, okay, I've received a PDF, so I'm going to take this route. So it's making a dynamic decision based on the inputs, okay, I've received an image, so I'm going to go and scan the image using an OCR tool, or I've received text, and therefore I'm going to take this route. So it's dynamically making that decision based on the input data, whereas previously in the non-agentic flow, it was just a linear flow; it didn't matter what the input was; it would always take the same actions. We've then got a validation step, so we will have another AI or LLM node that tells us and feeds back to the previous step, was that attempt successful? If it wasn't, then we have the chance to actually do it again and feed it back into the dynamic field extractor.

So in summary, this is an agentic invoice passer because it features multiple extraction routes based on these different file types; it includes confidence-based processing and actually feeds back information to itself to make sure that it's correct; it has access to these different tools, so it can actually dynamically choose which route to take and which tool to use; and importantly, it can refine its own strategy to improve extraction success. So based on the feedback, it can run again to make sure that we've got a successful run. So the thing that makes this agentic is yes, there were decisions on actions to take, and it took those decisions; yes, there is a feedback loop, I.E., it can process it on its own output again in a second run; yes, we can connect it to tools again, like the three we've connected to; and most importantly, it's got a variable output; we're not expecting a fixed output when we've got variable inputs; we're expecting variable outputs.

So we're going to go across now and understand how this presents itself in our workflow automation software, n8n. So when we consider our workflow automation platform, n8n, we have a bunch of different options. If you open up the nodes and open up AI nodes, you have a load of different options. You can see down this right-hand side; I'm going to explain now what makes some LLM nodes versus what makes some AI agents, and we'll cover the specifics of what is an AI agent within an agentic workflow.

So the LLM nodes, going back to our agentic versus non-agentic workflows, LLM nodes and workflows can be agentic only if you make them. So if we have feedback or decisions or we chain multiple of these together to create dynamic routes and actions, then they will be agentic, but they also cannot be agentic if we just had one basic LLM chain; we effectively using that like we would ChatGPT; we're just inputting a message, and it's retrieving a response and giving us an output based on its context. I'm going to quickly run through now all of the different LLM nodes that you can use and which ones you'll most frequently use for automating your business workflows in n8n. I've put them all on the canvas here so you can see exactly what they look like, and they're all connected to one single OpenAI chat model, but you can actually connect these to individual models; they don't have to be OpenAI; they could be any other platform, but it's just a demonstration; these are all connected to one model because you can actually do that.

Now, on the right-hand side, what you'll see in the tools bar are the different options, and each of these options have been created so that it's easy for you to understand which one you'd pick for a specific use case, but under the hood, it is effectively an LLM with a different system prompt designed to do a specific task. So take for example the information extractor; this says it extracts information from a text in a structured format. So this is just an LLM node, or we're just sending a prompt or an input to something like ChatGPT and a model of ChatGPT like 40 mini or 3.5, and it's just told to extract information, and inside that node, we tell it what information and what text to extract from. We then have the sentiment analysis, to which again is told, okay, we need to extract the sentiment, neutral or negative, from the input text, and that's really useful when you want to understand from a large piece of text or customer feedback whether things were positive, neutral, or negative. We could do the same with just an LLM prompt; we'd just change the prompt and give it more information about what makes a positive text, what makes neutral text, what makes negative text, but these are predefined nodes with prompts already made for us that make it easier to do certain actions. We then have the text classifier, which again is just a prompt that says classify this text into distinct categories, and it will have underneath some clear examples of categorizing that text, but at the end of the day, it's just an input and an output based on our input text. We then have a summarization chain; same here, we're contacting an LLM; we're using an LLM to summarize a block of text that we pass in, and then we have the most generic basic LLM chain, which you'll probably use the most because it's the most flexible, and we can adapt the prompt to how we want to see the output; we can give it clear examples, etc. The basic LLM chain is a simple chain to prompt a large language model. So this is the same as going to ChatGPT, choosing the model you want, like GPT 3.5, and putting in a set of instructions, a role, some examples of the output you want; we can do that all in the basic LLM chain, but it's still not an AI agent and not necessarily an agentic workflow. We can use this basic LLM chain, and it can be in a non-agentic workflow if we've got that linear flow; there's no feedback; there's no actions, and there's no decisions being made based on that information; if it's just a linear flow, input LLM output, then it's a non-agentic workflow. And for all of these LLM nodes that we've covered here, none of them can connect to tools; none of them can look at historic messages they've received, so they have no memory, and none of them can perform function calls. So they are simply input text and output text based on the content that you provide and its training data.

We finally have the question and answer chain, which which looks a little bit like an AI agent because it has a tool attached to it. So we can actually attach a memory to it or a database like a vector store, and this is an LLM chain designed to answer qu the input questions based on the attached documents. So this would be in the non-agentic workflow and LLM category because it's a linear flow; we're not asking it to make decisions based Bas on the data; we're asking it to retrieve data based on our inputs. So you can see there's quite a lot of LLM nodes in n8n, but they're designed to make it really easy to do specific tasks, but if we want to keep it more generic, then we're going to use the basic LLM chain and create our own prompt, and that's still a really powerful tool. And remember these can be agentic workflows or involved in agentic workflows only if you make them, make decisions, have feedback, attach them to tools, etc., but they also cannot be; they can also just be LLM nodes if that's what you need them for. And the idea behind this is we are trying to leverage the best thing for what we need for our business. There's a snippet I took from the n8n documentation here which I thought was a really powerful sentence that distills what an AI agent is versus an LLM. So while LLMs only process input to produce outputs, AI agents add goal-oriented functionality; they can use tools, process their own outputs, and make decisions to complete tasks and solve problems. So they've got a little table here of the features of an LLM versus an AI agent, and it just simplifies the view of what each of those does. So again, an LLM does not make any decisions; it's just generating texts based on our input query, whereas an AI agent is actually looking to complete a task and making decisions on how best to complete that task. So yes, it's making decisions; yes, we can connect it to tools and APIs, and it's given two clear examples at the bottom here. So an LLM can generate a paragraph, whereas an AI agent actually could schedule an appointment. And the reason we progress to AI agents over LLMs is when we want them to perform comp complex real-world tasks where they actually make decisions on our behalf.

So we finally got to it: AI agents. Understanding all of that is really important to understand exactly what an AI agent does. So I've got this great graphic I found, um, made by Cobus Gring, and I saw it first on LinkedIn, and it distills quite nicely everything we've spoken about so far that would make something an AI agent. So we've got the user input coming in on the left-hand side, then we've got got the LLM. So we always have some sort of LLM interaction here; however, the difference here is that the LLM is taking decisions and also to able to access certain tools. So for example, here it might have access to the web; it might have access to certain tools like a weather API, a math library, or calculator; it might have access to a document database like a RAG database; it's then going to make an observation, and based on that observation, understand if it's completed the task or not, and often it won't have completed the task on the first go, and we're actually going to cycle back and speak to the LLM again, which is going to give us the next set of tasks that we might want to take. So it might now say, okay, we want to search the web for more research, or we want to edit the content we've currently got; what tools do we need to do that? It's then going to pass the observation, and it's going to cycle through this loop probably multiple times, especially for complex tasks, and when it observes and understands that it's actually completed the required task, at that point, a final answer is reached, and it will send the output. So instead of just an LLM where we'd have the user input, the LLM straight to the output, we've got this observation and decision.

Phase that could include multiple external tools until the final answer is reached, and it's able to iterate on its own understanding as we go through to get to a better output. So you might be wondering at this stage, when in our business would we use an AI agent versus just using an LLM? We're going to get to that, but first we're going to cover the AI agent nodes inside our workflow automation n8n.

So, contrast to the LLMs, if you have an AI agent in your workflow, then they are agentic workflows by nature because the AI agent is making those decisions, taking action connected to the tools. So we're going to run over the key AI agent nodes within n8n and how you use them and why you use different ones.

The most familiar agent will probably be this tools agent. So inside our nodes, we can type in tools agent or AI agent, and it'll be the first drop-down within the AI agent. The description for this is: it utilizes structured tool schemas for precise and reliable tool selection and execution. It's recommended for complex tasks requiring accurate and consistent tool usage, but only usable with models that support tool cooling. There's a couple of key things we can take from that description. The first is that we use this for complex decision-making that might require EXT external tools.

So on the left-hand side, you can see that we've connected this tools agent to a series of different tools. The first is a database of memory, so we might use this to understand what a user has queried in the past. Say, for example, we're a customer service chatbot; we'd have that memory here. We might attach a company knowledge base to that so that it can search the company knowledge base and find the appropriate answer. We've then attached some more functional tools like an email workflow, so we can connect up other n8n workflows that conduct specific tasks. We might, for example, have an auto-emailer that is emailed based on the user query. This tools agent might have the ability to schedule calendar invites, and we'd prompt that inside the LLM prompt, telling it what information it is likely to send to the calendar. But again, it is an agent, so it might be able to interpret from the input data, one, if it's missing any information, but two, if it's got all the information, what information it should send through. And inside these nodes, when we go and build them out, you'll see that we're defining specific input parameters that we're sending to these tools. So, for example, a Google Calendar; we know to set up a calendar invite, we need to know several key bits of information: we need to know who it's with on their email, we need to know what the invite is about, and we need to know the time. So the AI agent, the tools agent here, is able to determine that info or work out whether it doesn't have the right information based on the user input and then use the tool if appropriate. And then finally, we've connected it to an HTTP request, so we're able to connect it to any API that we want, and this might be to PDF. For document processing, so say we receive a document in, it might understand at that point that we want to merge or split out a PDF and actually use that tool. But the key thing here is it's making a decision based on that and providing itself with feedback on the success of what it has done so far.

We then have the second most commonly used, which is a conversation agent. This is most similar to our LLM chain, but the difference here is we can give it a conversational memory. So this is great for chatbots, customer service chatbots, things like that, or company knowledge chatbots where we want to retain memory of what the user has said before. So we can connect it to a memory like an in-computer memory buffer memory, but we can also connect it to all the different tools that we mentioned. And on the right-hand side, you can see a sample of all of the different tools that we can actually connect it to. It includes things like Google Mail, Google Calendar, calculator; there's a lot of different, different tools, and they are always bringing out more tools that we can connect these agents to, making them even more powerful out of the box. And any that we cannot connect to, we can usually connect to through the HTTP request tool through the APIs.

There are some other AI agents that we've not touched on here that are available inside n8n and have each their own capabilities. You'll use the tools agent and the conversation agent most, but if you have specific tasks, then you might use, use the functions agent, which is excellent for tasks requiring specific structured outputs and specifically working with OpenAI models because they support function calling. You might use the plan and execute agent where actually your task is more planning-based and you need to solve multi-stage problems, and the agent is able to iteratively work through that problem, give itself feedback as it works through. The react agent is similar where it combines reasoning and action, so where we require careful analysis and step-by-step problem-solving, then a react agent may be good for your use case. And then finally, if we want to interact with our SQL databases, then an SQL agent is specifically trained on generating queries, SQL queries to reach from our database.

All of this theory is no good if we don't know how to apply it in certain situations. So we're going to go through now a few different business cases where we might use a non-agentic workflow, an agentic workflow, and what an agent might actually do in that scenario, just to give it some life and see, help you to understand, help us understand exactly how we might use this in our business.

So we first have a customer support workflow. So we want to enhance our customer support processes, and we're going to do that using workflows. We could have a non-agentic workflow, and this might be where we have a linear flow; a chatbot follows a predefined response template. So we have a series of questions and answers that it's able to use, some fixed escalation, and some fixed escalation paths based on certain keywords that trigger it. So this might be a chatbot that's just trained on our FAQs but isn't able to think on its feet and able to perform more actions than just sending escalation or returning an FAQ answer. If we were to make that agentic, then the things that we might include are a human feedback loop, so we might be able to escalate to a human who gives us feedback, and then our agent or workflow is able to adapt to the human's feedback. We might have dynamic response generation, so it's able to think about, based on some context, what it should respond rather than sticking to the predefined response templates. And then we may have different scenario routing based on, based on things like: does the customer want to place an order? We will take this action with the customer or send them down this route. Does the customer want to escalate to a manager? We'll take them down this route. So it's able to think about what the customer is inquiring about and use appropriate routes or tools and dynamically choose those. And an AI agent within that might be able to use those different routes that we mentioned, so multi-channel support management, but also use its understanding of sentiment analysis to understand how do we prioritize these queries coming in.

Going down to sales, we might have manual lead qualification for a non-agentic workflow with fixed outreach templates, whereas an agentic flow might be able to work out a lead score based on the inputs and dynamically choose the root, route that that lead goes down and choose a personalized approach for that customer. And the AI agent may help with that lead qualification and scoring as well as personalized outreach or meeting scheduling.

For content creation, you can see it follows a similar gist, which is non-agentic workflows may be creating content based on our template inputs, whereas an agentic flow may be able to conduct real-time topic research and optimize and change the templates based on the content or research. The AI agent as part of that might be doing the topic research, conducting web searches or SEO research as well as referring to our brand voice guidelines and able to dynamically adapt our content to the brand voice.

The final example we have here is document processing. So again, non-agentic would be a linear flow with no feedback loops, and we covered this in the invoice passer part of document processing. An agentic flow would be able to dynamically extract data based on the content that's input based on its understanding of what we want to output. So if, for example, we told it to split the PDFs, it might reach out to the split PDF API and understand that it needs to perform that action and understand whether that action has been performed correctly and whether the inputs we received in the first place were in the right format to do so.

So that rounds up AI agents, agentic workflows, and non-agentic workflows, as well as how all of these things can be used to enhance certain processes in our business. Now coming back to the context of what we actually need AI for here, we are processing some data from a file and trying to extract key info using an LLM or a large language model. So we could use something like a prompt, but like I said, most of the time we're actually going to use an LLM chain where we can give it a set of instructions and tell it: these are the different items I'd like to look for in the email, please extract those and put it in a certain output. And we'll run through that in a moment, how we get a certain output and what the prompt looks like. We don't necessarily need to give it any tools; we're not outputting data into different tools like a CRM; it's all going into one place; we don't need any web search, so we're actually not going to use an AI agent in this case, and we're just going to use a basic LLM chain. So we're going to drag that up here, and the first thing you'll notice that we've got is a model down here. So we're going to open up the node, the basic LLM chain, and you'll have two options here: you'll have a connected chat trigger node, which will be there by default, which means we can pass in a chat message from a previous window as the system prompt. So the prompt is just what you would normally type into ChatGPT or Claude; it's just the message you're asking it to, or the task you're asking to perform. We're going to define that below, and it will just appear as this text field. And you can see we've got these warnings because nothing's been filled out. You can see here we've got: require a specific output format. For now, we're going to leave that as not ticked, and you'll see the variable outputs you get and how to correct those. And then down here we have these additional options; it will start with none, but by default we will add a system message, and the system message it should use. And then all we're going to define in the user message or up above is what inputs we're actually providing to it. So we're going to want to pass the text in because we're going to extract key info from the text which has been pulled from our file. It's important to note at this point, you cannot pass a binary file into the LLM; it only understands the text that we pass into it, and that's why it's so important early on that we pre-process that data and format in this way so that actually when we pass that text through, you can see it's very clean text that it can just read through and extract key info from.

Now you'll see a lot of contradicting advice around how to prompt properly, but also lots of useful advice; you need to work out the style that suits you. For me, I fill most of the information in the system message, and then I tend to just put the inputs directly once the LLM understands what its role is, what the outputs I'm looking for, the inputs are the only thing I put in the user message. But try out different methods; see what works for you. You can add all of this prompt into the user message in the text up here, or you can add it all into the system message; it's entirely up to you. So I've got a prompt, if I open up here, that I've previously used for an invoice passer, so I'm going to paste that in to save us some time. But what we're going to do now is run through the important details in this prompt. So I've effectively given it this role: given the following invoice in the invoice XML tags, so I'm going to pass in an invoice or the text of an invoice, extract the following information as listed below. So I've told it what its role is. If you cannot, there we go, got a mistake, find the information for a specific item, then leave blank and skip to the next. Sometimes LLMs can get stuck if they can't find certain information we've asked it for; this just gives it an out so that it will not keep searching and will save its time and just jump to the next. Not all of these are required, as you'll see. I've then got a bullet point list which I've done with stars because that's markdown format, but again, this could be a numbered list for you; it could be dashes; it doesn't matter; it's still going to interpret it the same, but I just tend to use markdown um because LLMs are trained on markdown. So we said: gather these items, the description, a short one to two line description of the invoice, e.g., monthly database usage for Superbase. The reason I've given it examples is because you should treat a prompt like you are training a human how to get the same output. So if you were to just give these items to somebody you were training without giving them examples, you would probably get variable results. So if you give them an example of what good looks like, then it can consistently relate to that example and actually pull more relevant information. So examples in your prompt are really key to getting it to a really good output, consistent output which you need for business use. So we've told it to pull a description; we've told it that we want a type, so I've given it some options here; you can either choose monthly recurring, annual recurring, or single payment. So we're referring to invoices here, so most of mine fall under one of these, and I want to know when I'm reconciling, was it a 3 $99 single payment, or is that a monthly recurring thing that I need to check out? We then pull key info around invoice date, payment date because it's not always the same as invoice date, the invoice number, and you can see I've specified that these are required, and the LLM chain or the model that we connected to will understand that it needs to pull those every time. And then we've got lots of different information that we're pulling from the invoice, and you can go in here and change it and remove things, but we're effectively specifying all of these different things that we deem important to pull from the incoming text if it finds it in the incoming text. I've then added this almost like a catch-all: additional information you deem important that isn't included above, and then we've said: additional important information such as payment terms, payment methods, tax exemption, references, delivery terms, special instructions. So things that it might not pick up in those categories but we might want to know when we're reconciling invoices as you pull. So you can see I've given it clear examples of things I want it to pull, and that is all in the prompt, but you can see there's no inputs here, but we've told it to and expect an invoice input inside of these invoice XML tags. So to make that really clear, we're going to go into the user message up here, and we are going to add these XML tags, so the opening and closing tags here. And again, you don't need to work with XML; that's just a preference; you could instead just say invoice or just pass in the text, and it would understand that that is the invoice, but I prefer to just specify in the system prompt and then call out the same things because when you've got multiple inputs, that becomes more important. So we're going to give that a run now, but you'll notice that it will not run; you'll notice that we're missing one final thing, which is a model to connect it to. So down here we can click plus on the model, and on the right-hand side, we get given the options for all of the different model providers that we can connect to. So ChatGPT, for example, uses OpenAI; it's a model from OpenAI. Anthropic gives us Claude. Google Gemini. The majority of times you're going to use OpenAI or Claude. And a way to do that is actually to use OpenRouter instead. So if you've been keeping up with AI news, you'll notice that there's a new model coming out every single week; all of the providers like OpenAI, Anthropic, DeepSeek are all competing against each other to get models out that are better and faster and better at certain things like planning or research; there's lots of deep research nodes coming out at the moment. So you want to stay as a business model agnostic and use a platform that enables you to switch models very, very quickly and very, very easily. So instead of hardcoding these models like openai chat model into here and being stuck with OpenAI and having to update our API key or update our keys when the model changes to the better model, changes to a different provider, we can use something like OpenRouter, which in n8n has its own model, and we can use OpenRouter to connect to any model we want with one single key. So if we go to OpenRouter's website, it says: a unified interface for LLMs, so you can access any large language model, or thousands of them, through one key for very minimal costs; basically the cost of what it takes to use that API through the official routes anyway. And on here we can go to models, and it will have all of the lists of models, but we know that the ones we conventionally use are ChatGPT 4 0 mini or so. If we type in 4 mini, that will appear below, and you can see that if we click on it, it will give us all the details around cost. So it's 0.15 per million input tokens and 0.6 per million output tokens. Treat tokens like characters. So 15 cents per million is going to be hundreds of pages for 15 cents, so this running this automation is going to be extremely cheap unless we have hundreds of thousands of invoices coming in. Models that are better at writing like Anthropic's Claude, Claude 3.5 Sonnet is much more expensive, so you can see it's $3 per million input tokens. So I recommend starting with a cheaper model, seeing how it performs, like 40 mini, and then if it's not performing up to standard, you can switch the model; that's the beauty of OpenRouter. So we're going to go into our OpenRouter chat model here, and we're going to go to the credentials, and we're going to create a new credential, and you can see up here that we can rename it again, so we'll say uh test for demo API key OpenRouter; obviously you'd use better naming than this, but we go back to OpenRouter, and you need to sign up for an account first. So once you signed up, sign back in.

So once we sign back in, on the top right-hand side on the dropdown, you can go to keys and set up your new key, and we'll create a test demo key, and it will show your key on screen. We're going to copy that key, and I'll delete this afterwards. We're going back to the test workflow, copy and paste that into our API key, and then once that's saved, that will confirm that our credential is ready to use. You need to make sure that you've got enough money in the account, so you need to go to credits and make sure you top up $5 to $10. You can see 14 days ago I topped up $10, and I've only used 90 cents since then, and I use this consistently every day for various things, so very cheap if you use the right models. We'll come back to the test window, and we're going to come in and refresh the list here, and this will give us access to all of the different models. If you're experiencing this issue, which I've been facing with the OpenRouter model, there is an alternative way to access OpenRouter, which I'll show you now. So I've just tried to run it, and it's come up with an authorization failed error. So actually, I'm going to show you how to use OpenRouter, but if yours also doesn't work, then you can use it through the OpenAI chat model, and what you can do is create a new credential with that same API key we mentioned before. If we come in and open the credential, then you'll see here's where we put our API key, and the base URL you need to change the update to be OpenRouter and not OpenAI. So it's this address exactly: AI API V1, and that will be enough to connect to OpenRouter. And then instead of from list here, if that doesn't show up, we can copy the model name from here, and we can put it in as an expression, but it should show up here from list and allow us to pick GPT 4 0 mini, which is the model we were going to choose. So now we've connected that up, let's just name that Open, OpenRouter, so that we're clear on what it is, and we'll delete this OpenRouter official node. So now we've connected to a model, we can actually run it. And now that we've run it, you can see it's come out with our first outcome. So we've got the file; we've processed that into text, and we've actually then returned an output, actually outputted all of the text we've asked for. So it's given description, uh the type, the invoice status, the supply name, and the invoice number, and we can go and check the invoice number ends in 00004 against the actual invoice. If we scroll up, we can see that the invoice number is in fact that correct invoice, and the total amount due is 2640. We go back here, and it's recognized the total price is 2640, so it has actually pulled all the information we need, um all the information we've asked for, or where it can pull all that information. However, if we ran this several times, it might come back with different headers, although we've told it in the prompt to specify all of these outputs; we've actually not, it's still is using its own judgment on what to return because we've not actually given it a specific output format to require. So if you click the require specific output format, we're then going to tell it exactly the output format we need. The way it's outputting right now is not any good for us for inputting consistent data into our invoice system or our Airtable where we're storing the invoices because we'd then have to break up all of these different fields again by split lines, and it wouldn't be easy to do that consistently. The output we've received here is a text paragraph, and to extract consistent data with which we need for our business to pass and reconcile invoices, we'd have to split all the different fields here. So there is a much easier way, which is actually just specifying a JSON output for the model to adhere to, so every time it gives us the same output format and make sure that that's correct before it outputs the data. So we're going to turn this require specific output format on, and that's going to give us a second uh thing to connect to here. We're going to click inside that, and we've got three options here: we've got the auto-fixing output passer, which is the one we're going to use, and what this does is automatically fixes the output if it's not in the correct format. So we're going to specify an output format that we want, but this will automatically fix it by calling the LLM again rather than us having to tell the LLM that's not right, try again; it will do that automatically, and we don't even need to prompt it to do so. And then the, the other two are an extension on that, which are what, what type of format do we want it to return in? So we're going to click the output, auto-fixing output passer, and you can see that we connect a model and an output passer again, so the model.

We're just going to connect to our open route model and the output passer. We then open that up, and we have two options: we can return the list as a; we can return the results as a list of separate items, or we can return a structured JSON format. I recommend using the structured JSON format because then consistently we can return the same data every time, and it's really, really accurate. And that's something we need when we're reconciling invoices; we need the exact fields to be present each time. So there's two ways we can generate this: the first is from a JSON example like below, and we've been dealing with JSON data all throughout now; or the second is to define the schema. Man, we will just do the first one to show. So we're going to put in description here, and we're going to put in total paid here. And all we're going to do is tell it, give it an example of $20 in total paid, and description is 11 Labs bill. So we're going to run that now, and it doesn't matter what we specified now in the prompt to output; it will output; it will fix the output to be just those two fields. So you can see now in the output that it's output as we expected: description and total paid, and it's, yeah, given the description there, and total paid is 2640, which is extracted from the text. So that works well.

If we want to pull all the fields that we specified in the initial prompt, which you can see were a lot: description, type, invoice date, payment date, etc., then we could go through and write all those fields out. The alternative to that is generate it from a JSON schema. And the benefit of generating it from a JSON schema is that you can be more specific with the type of data being passed through and also whether the field is required or not. So you can see this is more complex, and it's a JSON schema format. Don't worry about this being complex; there's a really easy way to generate it. If you copy and paste this into ChatGPT or Claude as an example, and you also copy in all of our inputs from the prompt, or sorry, outputs from the prompt, and what we want to achieve or what we want to output, and say, "Take these outputs and turn them into a JSON schema like the attached JSON schema and include this as an example," it will then come up with a JSON schema in this format that's really specific and consistently gets good results using our LLM. So I'm just going to copy and paste in the JSON schema that I previously made from that, and you can see it's got all of our different fields here, all the different nested fields, and also specifies where the things are required and the data types like strings, dates, etc. And that's important when we're passing back into our Airtable because we need to match the data types there.

So if we run that again as a test, you will see that the LLM will start running, and it will call the open router model and also check against the required output to check that is met the requirements, and it will show green once it's met the requirements. So we now go to the results of that, and you can see it's got a much more detailed line-by-line JSON format that has all of the fields that we asked for, including supply name, customer name, any additional information, etc. So we are at the point now where we've almost implemented a full document passer with just a few key stages. We've also covered the key fundamentals and the key building blocks in n8n workflows and how to connect those and pass through the inputs and outputs, as well as how to manipulate data in the other workflows that you end up building for your business or for other businesses. You will use all of these fundamental building blocks at a certain point in time. The fact that you've got this far means that you're already ahead of 90% of others that are building using n8n, so well done for that. Now let's do the last step of connecting your data, and then after that we will move on to more difficult data types and how to master connecting to external data types and external APIs.

The final step here is connecting back to our database or our Airtable where we're going to put the data into. So we're going to go to Airtable, and we're going to open up a new table and import like we did before for the emails: a table called Financial, or called Invoices, or whatever, and give it these fields: invoice number, description, invoice date, payment date, type, total price, current y line items, purchase order number, supplier name, supplier VAT number, additional info, and invoice URL. The invoice URL is only going to be relevant if we are pulling that initially from a Google Drive file. So because we're doing this with Gmail, it's not going to actually populate with anything useful, but if you're pulling from a Google Drive in a future workflow or you want to replace the trigger, then the invoice URL will link you directly back to the invoice. You're going to see our results populate exactly like this once we run the flow and once we've mapped the fields. If you want access to the Airtable to just copy it directly, as well as the finished workflows, then you're more than welcome to join the School Community; it's school.com/scrapes, and then within that, within the community, there is a classroom section. You can go to the free course, and there'll be all of the core concepts that we've covered today, and there will be all of the templates within those. So just find the appropriate lesson for this one, and there will be a template attached to the bottom that will give you the fully working flow.

Anyway, back to the flow. Let's go back to our n8n flow, and we now know we have the output. So what we're going to do is connect our previously made Airtable node, and we're just going to need to map those outputs again. So it's no longer going to be post emails, and it's going to be post invoices. And you can see all of the fields that we had before are no longer relevant because we need to update the table we're putting it to. So mine is called Financial, and then again we're going to map each column manually, and we have all of the columns from our basic LLM chain output that we can just drag and drop into there. And remember for these that we want to make it future-proof by just adding in the actual node name, so we've got basic LLM chain.item.JSON, and then the field, so we can drag and drop and then update those. So I'll go through and add those now. Whoops, that's the wrong one. So I'll just make sure it's the correct field, that's invoice number now. So we'll come back into the node, and you can see I've mapped all of those data fields now referencing the basic LLM chain outputs, and what we're going to do is just test this step. Okay, so we've tested this step, and it's actually thrown an error, and this will happen often when you're running these. So it says, "Cannot pass value 26.4 for field total price." So this will be often, more often than not, a data type issue. So in our scrapes table, we've got the total price, which we've given a data type of a long text, so we've called this a string; however, when we are creating the structured output passer, if we go to total price, you can see that we've given it a data type of number. We've done that with a few other things as well.

So there's two ways we can tackle this: one is the slightly easier way, which is to add options and type-cast the responses. So this just means that the Airtable API will effectively attempt mapping the values that we're passing to it to the fields that it has. So let's try that first, and actually that's done it successfully. It's effectively converted our number that it's received into a string value in our table, and that's fine because we can manipulate that in Airtable directly. But you can see that it is now put in the correct values for our invoice that we've been processing, so it's got even a breakdown of all the different line items as per the invoice, the supplier name, the VAT number, additional information, etc. Now you can notice the above invoice is one I've already processed in the past, and actually they've got the same invoice number. So there's two things to note here: one is that it's adding records and not updating records, so if we want to do that, we can go back and do that in a second because actually we don't want duplicate invoices appearing here. The second thing is that actually some of the information has changed between the first time we run it: monthly recurring, and the second time, and now this is just the state of what LLM outputs are like; it's not always going to perfectly identify that information, but it does 95% of the job for us. You would know by reconciling this invoice that actually it's a monthly recurring cost, not a single payment, and actually then you change that there. It's also misidentified the currency here as GBP versus USD. So again, it's not perfect, but it does 95% of the job, so that we can just come in here and reconcile the invoices on a monthly basis.

So we're going to go back to the Airtable and just make sure that it's updating instead of adding a new record, and then each time it will check invoice number and it will then or change the details on that invoice directly. So we're going to go up to here; instead of the operation create, we're going to have create or update. It's going to give us one additional field here, which is columns to match on. So, like said, we're going to match on invoice number, and actually now this has changed to invoice number using to match, and if we delete this row here, you'll see that this will change to a single payment; this will change to GBP like we saw before because it's just updating this invoice. So we go back here; you can see the automation has come in here, and it was changing all those values, so those are all updated; it's now updating or appending if the invoice doesn't exist. It's a really, really useful business tool that you have just created from scratch. And that concludes the second automation that you've built completely from scratch, and this is a really powerful one that takes into account a lot of different concepts that you will reuse again and again when you're creating new automations using n8n. We're now going to look at how to manipulate and read external API data sources because quite often you'll be interacting with softwares where there's no pre-built-in nodes, and I'm going to show you exactly step by step how to do that.

So we've now completed the core concept stage where we've built the fundamental building blocks and shown you around the canvas and the different data types and how to use them in n8n. We have shown you how to work with your own data; use an example where we build out a mini automation to send our emails to Airtable; and then we, from start to finish, created a complete invoice passer system that connects to your emails, extracts the invoices, and passes them using an AI node and then puts it into Airtable. What we're now going to do is step one level up, and where the data is not accessible or where you cannot connect to the software directly inside n8n, we're going to show you how to connect to anything using APIs. The best way to explain an API, if you've not thought about them before, is to think about them in terms of what we learned already: so the n8n nodes. So we might have something like Airtable that has a pre-built node in n8n. So in the back end of n8n, an Airtable is actually just being connected to using that API, which stands for application programming interface, which is just a fancy way of saying the Airtable allow you access to their data or to your data that's behind the API by a preconfigured or pre-set-up connection, i.e., the API. So when we're using n8n, n8n is actually just a series of APIs connected to certain servers like Airtable.

Now, if we go back into n8n, you can see in the action in an app that there are hundreds, and I think thousands now, of services you can connect to with n8n: Twilio for voice calls, Webflow, WordPress, YouTube—a lot of different services. But sometimes they don't have a pre-built node; connecting to those APIs for you, like the API, like the Airtable node here, makes it really easy because it's connecting for us to the Airtable API. But sometimes you want to connect to a service that has an API but does not have a pre-built node; that's how we can use APIs in n8n. So to connect to a service like Airtable, we'd need to send data to Airtable itself, and what we're receiving is data back; the same way in which when we send data using the Airtable node, it then puts it into Airtable, and we receive a response from that. So the way to do this is just called an HTTP request, and you guessed it; there's a node for an HTTP request in n8n that we can leverage to do this. When we are interacting with APIs, they commonly use standard terms: we use POST when we are sending data to; we use GET when we are retrieving data or reading data from a service like Airtable; we use PUT where we want to update all data—not as commonly used; POST and GET are the most commonly used; we use PATCH when we want to update some data; and we use DELETE—self-explanatory: delete data. So these are the requests we are sending to the Airtable server or API, and it gives us back a response. That response will tell us if the request has been successful or unsuccessful. So we will receive codes back along with data. So if the code ends in or starts in 200, it indicates a success; certain other routes like 400 might be resource not found. You don't have to worry about the codes, but you will receive a code back that's either success or failure with detailed information.

So you can think of it as an HTTP request is sending or asking for data from a service like Airtable that has preset up a series of retrievable information. We retrieve those from what we call endpoints, and endpoints you'll see is just the URL that we're contacting or the end of the URL that we're contacting to get that information. This will become really clear when we start interacting with those APIs, and we'll show you exactly how to read that API documentation in order to get any data from any API. So you can see how powerful this becomes because for your business use cases you can manipulate your data but also share it with other systems automatically without having to lift a finger. So if we come back to the workflow here, we're going to again open up the nodes; we're just going to type in HTTP request, which is exactly what we were talking about; we'll make sure it's not connected to any other values, and we're going to start a new flow down here. We're going to demonstrate this by using a service that automatically passes invoices for us, but actually that's a free-to-use service where we get a free trial, and we can just, instead of doing all of this processing, we can just contact that service, send the information about our invoice, i.e., the PDF file attached, and it will return to us exactly what we've done here with the LLM node. So it will show you a like-by-like comparison using an external service that's pre-built exactly for this. So we're going to give it a go with a service called pdf.co, and they are a service that are API accessible, and they automate tasks like PDF conversion, editing, extraction, and other things like invoice passing. So say, for example, you were setting up an automation in n8n, if you connected to pdf.co, you could really easily do what we've already done quickly: I pass the invoices directly using their service and their API, but you could also just switch the endpoints, which are the connection or function points for us on the HTTP request, to do any other thing like convert the PDF to anything, pass the documents, classify the documents—all of these different features that might be readily accessible out of the box using an API that are not native to n8n. So you can see how this can become really powerful for your business use cases because there's always services like this that are accessible externally through an HTTP request.

So I've not used pdf.co before, so it will also be a learning experience, and you seeing exactly how I navigate the documentation to understand how to create the HTTP request here. So we're going to sign up, and you sign up. So once we have signed up, we'll be greeted with this app.pdf.co homepage. It tells us we can view our API key here; they have all the different tools listed out there; they have your API call log history, and you can manage your subscription plan. Right, we've got 10,000 free credits, and there is our API key, which we're going to need, like we do with all of the other nodes, to contact and authorize that it is us sending the HTTP request. So we're going to go to the documentation. So if we go back to the main page, main homepage, they have an API docs button; we'll click on that, and it's already a good sign because they integrate with low-code or no-code softwares, and they've got Zapier and Make on there, which means in n8n we'll absolutely be able to connect to this API. We'll go to the API documentation, and often it will be very heavy on text; don't be put off by this. If it's got more text, then there's likely more endpoints that we can contact, more things we can do, and it kind of opens up the opportunity for us. I can already see immediately on the left there's some things that are interesting: we've got the AI invoice passer; we've got a document passer; so we might need to use one of those, um, in particular the AI invoice passer. We've then got some endpoints probably for PDF to CSV, PDF to text; so converting from different endpoints and lots of different functions that we can use just through one single API; really, really powerful. I would break down an API or HTTP request into two things: the first is your authorization; so we need to authenticate that it is us sending the request, and we'll do that in a second through the traditional HTTP request credentials; and the second thing is what are we asking for? Are we retrieving data using a GET request? Are we sending data using a POST request? And in this example, we're going to be sending a PDF directly from n8n and actually passing it like we did previously but using this HTTP request to show the difference. So we're going to go back to n8n, and we've got the HTTP request here; we're just going to jump into the node, and you can see immediately that we've got all these things we spoke about: we've got the GET, we've got the POST, we've got the DELETE, we've got the PUT. First of all, we're just going to change this to POST because we know posting data; the URL in here is the URL we're going to make a request to; so it will tell us that in the documentation. So we'll now tackle the first part, most important part, which is authorization: so validating there is in fact us contacting the API. So in the documents, you're going to click on authenticating your API request, and it leads us to here where it says to authenticate you need to add a header named X-API-Key using your API key as the value. So we know we need to pass a header in to our HTTP request; needs to be called X-API-Key, and we need to add our API key as the value. So if we go back to n8n, inside authentication, we've got two options here: we've got a predefined credential type; so if there's a service already set up inside n8n, then it might have a predefined credential type like Google; if not, however, like pdf.co, then we're going to use a generic credential type. There are multiple here, but it's told us we're going to use a header auth type, and this might get pre-populated, but what we're going to do is go and create a new credential here. As always, we're going to rename it because it's going to be easier to find in the future, and we'll rename it with the auth type and the name of the service: pdf.co header auth. It told us in the documents that we need to put in X-API-Key, so we'll go and copy and paste that, and then then it told us in the documents that we need our API key as the value there, so we'll go back to the dashboard, and we're going to copy our key that's obfuscated at the moment; we're going to go back into the value column, and we're going to save that. Now that's going to confirm it down here, but it doesn't necessarily mean it's correct, but we'll go and test that in a moment. The other type that you'll often see for header auths is typing the word Authorization with a capital A in the name, and then I'll just delete that out so I can show you; we'd have Bearer with a capital space your API key afterwards. That's a common header authorization format type that you'll see again and again, so that might come up, but for this one we know that it's just X-API-Key and our API key value. We're going to save that; we're going to come back out. Now we will look at the different values that we pass in the body; so that's our header; so we're now going to look for what URL we need to contact for the endpoint and also what data to send or retrieve and how to do that. So in the docs, it gives us this really important note, and we will always talk about the base URL; so all of our endpoints will be on top of a base URL, and that will make sense when we come to it, but this API base URL is going to form the starting point for our URL that we're reaching out to with the request; so any endpoint will have a forward slash, and it'll be endpoint one, endpoint two, and that might be invoice passer; we'll see what it is in a minute, but it might be something like invoice passer, but always will share this base URL. So we'll get rid of that a second; go back to the documentation, and we're going to have a look at the documentation for the AI invoice passer. So we'll click on that; you can immediately see the available methods are POST, and it's told us the endpoint, which is /v1/ai-invoice-passer, and here we've got a more detail method endpoint. Now API documentation will all be slightly nuanced; it might read differently on different services, but the core concepts remain the same: we have a method—are we retrieving data or are we sending data—and an endpoint, as well as then the attributes or the the attributes that we are sending in that request, the HTTP request, in order to get a response. So here we can see that the endpoint is /v1/ai-invoice-passer, and it's actually just ai-invoice-passer because we already had that on the base URL; so like that we just append that endpoint, and we can try to just do a GET request there and test that step and see if it responds; and of course there was no GET method, so it says the method is not found. But sometimes we can just use that to test the that the authorization or the header we're sending is correct. So we'll go back to the POST method; we will try it again, and it's telling us invalid input URL. So what I'm reading from that is actually the header auth is working, but it's telling us we need to append more data because what we're actually asking it to do is we're asking it to receive the data we're sending, and then we're sending no data. So we'll go back to the docs again, and you can see that for this AI invoice passer it gives us two different attributes that we're going to send: we're going to send a URL, and it's also asking for a callback, but only the URL is required. So the URL will be a URL linking to our source PDF, and you can already see how that's going to be an issue because we have a binary data file and we don't have our...

PDF uploaded somewhere, so we'll tackle that in a moment. And then the Callback is a slightly different concept, and it will only be used sometimes, but it's not required here. The Callback URL is effectively saying that once the invoice is processed on pdf. CO's server—once we send the invoice—it's going to be processed. Instead of waiting for that and calling it again, it will actually just send us the details back to a web hook where we will receive the details back to us instead of calling it again to retrieve them. So it's a way of them sending data to us, where the web Hook is acting as our API.

The way you can set that up—and we won't go into this right now—is to go to the nodes and hit web hook, and there'll be a web hook trigger with an address here that we could send to pdf. as our callback URL. We'd use this production URL here. For now, we're going to delete that web hook and just see what our response is when we send the URL, as we've already mentioned. Our file that we were using before—our invoice—has not been uploaded anywhere. So often services like pdf. will have a way to upload a document temporarily to get a URL so we can send that URL in the HTTP request. So we might need to make another HTTP request before this one in order to upload our binary document first. So we'll have a look through the docs here, and I can see a file upload endpoint. You can upload files as tempor pre files into pdf. I.E., they'll be stored for an hour and then auto-removed. So we can upload probably a binary data file up to 2 gabt in size using a different HTTP request, and it gives us the step here. It says call this endpoint, which again we will do in a second. It will generate a link for the upload; it generate a link for uploading. So we call that first with the get request; we then post our binary data or our PDF file to the URL, and we'll be given a URL that we can then use in the next request to process or pass our invoice.

So it's a slightly more complicated API setup, but gives you a really good idea of how to read through this documentation and work your way through it. And I'll show you afterwards a really quick way to set up these API requests that will save you a lot of time. But first, we're going to go through step by step how to set this up. So back in the API documentation, we have the steps here. So we need to first use a get request to get this pre-signed URL, of which we're going to upload our binary file to. So let's create a new HTTP request here, and what we can do is just copy and paste this HTTP request. It will appear somewhere on the canvas; we'll rename them shortly. We'll go into it, and instead of that we're going to do it a get, and we're going to make sure that we have the the right end point here. So we have SL fileupload get pre-signed URL, and because it's a get request we don't need to send any information. We're just going to rename this get URL for upload, so it's really clear what we're doing. Let's test that and see what it comes back with. So it's come back with a successful response, and it's given us this pre-signed URL, which it told us it would, and also a URL. So now let's just go and understand what those are. Use the pre-signed URL to upload your file. Once you upload your file to this pre-signed URL using put—so not post—we use a put request; you can use the URL link to access the uploaded file. Okay, so we upload the binary data to our pre-signed URL. So we're just going to copy this Google Mail trigger down and the notes, so we're keeping good record. We're going to run the test event again, and it's the same one we had before. We're going to change this from a get to a put because the documentation told us to. So we've got the binary file coming in there; we've got our URL here which we need to upload, and then we're going to use the learnings that we applied earlier and actually merge those together so that we pass through both the file and the URL. So we going to pull the merge node up, and if we just run a test on that both or add, sorry, if we we just add an a manual trigger and on our merge node we're just going to wait for all inputs to arrive, and then we're going to run a test on that, and that should run both of our branches on the left hand side. So on the right hand side it's passing through our data, and that just means that both of these have now run. So we've got the pre-assigned URL which we need to upload the binary data to, and then we've got the binary data from our Gmail trigger here. The binary data, as a reminder, is just our PDF file. So now we need to upload our PDF file using put to this pre-signed URL.

So one thing important to note is here it's a put method, but also we need to replace on the endpoint our pre-signed URL, and then it's given us a reminder that we need to add content type header and tell it what content we're sending. In this example, it will be application PDF. So let's do that now. So we're going to create a new HTTP request. I'm going to paste in the URL and go back to our previous node to get the base URL again. So we're going to upload to our pre-signed URL. So we already know that we got our pre-signed URL here, and get URL for upload it returned our pre-signed URL. So we're going to need to reference that using an expression and replace it here with get signed pre-signed URL. So we're going to go back on the schema, which which an easy way to visualize our inputs, and we're going to go and drag the pre-signed URL into the box here. Now you'll see now you'll see that this comes up with no path back to node, and this commonly happens when you merging nodes; you can't find the path or it can't find the PATH back to this pre-signed URL. So all we're going to do is we know that there's only one pre-signed URL, so we can change this from detecting each item of every iteration and just write the first item, and now you can see it's attached the pre-signed URL to the end of the request. We're going to make sure our authentication is correct, so we need our header or and we need it to be the pdf. C header or, and then let's go back to the documentation and see what we're passing. So we're adding a content type header, so we will send headers, and we will put content type, and then we know we're sending an application SL PDF. I'm just going to copy it from across there. I believe that's correct; yeah, application SL PDF. And then in the body we're actually sending a binary file, so we're going to send a body, but instead of the body content type being Json, we're sending an N binary file, and as we saw before we know the attachment name is attachment one, for example, and we're just going to rename this request to send PDF to PDF Co. And there's one thing I've forgotten here, which this should be a put request, so actually I'm just going to also rename it to put PDF to PDF Cod, and then I know exactly what is happening there is updating the URL on PDF code because remember put updates values on there. So we're going to test that step now and see what it comes back with.

So this is a good lesson in reading the documentation correctly, because I misunderstood, and I ran it, and I was actually contacting the wrong endpoint. So I've gone back to the documentation, and what it actually said was that the put endpoint is just the pre-signed URL, so no base URL this time; we just have that pre-signed URL and then send our binary data. So I've just put in the URL, our pre-signed URL, which is this temp file Amazon AWS server; we've put in our headers; we put in the content type as application PDF, and then we've attached the binary file. We've run that, and it's come through as successfully, but it's also returned nothing, so it doesn't give us much of an idea. So the next thing we need to do is actually then retrieve that URL or pass that URL into our invoice passer. So we've effectively uploaded the file now; it's going to stay live for an hour. So we now need to create the next step, which was the starting point, which was our original HTTP request where we are passing through the URL to get processed as an invoice. So we'll go back to the AO invoice passer, and we're back to these docs where we're posting the URL, and all we need to do is go back to the requests. We're just going to name this now call post PDF Co file; post PDF file we'll call it, so we know that that has now been processed in the previous node. So in the body we are going to send Json content type this time, and we're going to fill out these attributes, and we know that only one is required, and that's the URL. So we're going to fill out the URL. So the way we do that is we go into our body parameters, and you can either do this using Json and actually just copy and paste this in here like this; this would be perfectly valid, and we replace this with the expression, or we can use the easier naming convention, which is using the fields below. We just put an URL, and again we know we're pulling the URL from a previous value, and we're pulling that from our get URL for upload; it returned the URL here, and again we've got the same issue where we should just reference first. We can actually test this by just going directly to this URL, and it should allow us to download the file, or it should show us the file that we were had in question. So there we go; at that address it's now tempor temporarily uploaded our file so that we can send it into the invoice passer, so that should be everything; it doesn't say to add anything else. So if we now run this post PDF file, what it's going to do is send the file in order to get ped, and it's given us some status details. So it's given us a job ID; was there an error? No; status 200, which we discussed was success; we've used 100 credits; we've got 9886 remaining, and that action's taken no seconds, but now it's going to be processing the background. So we didn't give it that call back URL to send it back to the web put. So now we've somehow got to retrieve that from the request.

Just to mention at this point, not all API or HTTP requests are this complex when you're handling data types like this. This is definitely far more complex than if you're just posting data or retrieving data. Once you've got to grips with this, everything else will be really, really straightforward. And I'll also show you in a second how to speed up the process of making these HTTP requests, or speed up the process cess of reading the documentation. So I'm reading the documentation here, and under the AI invoice passer it mentions that we can use the job ID to identify the corresponding uh callback response; use the job check API endpoint to poll the job status. So we're going to go down to the job check endpoint here, and we're going to use the job ID and make another post request to check on the status of that. So we'll copy this endpoint, go back to the canvas again, we'll set up a new HTTP request, or we can copy and paste one of the old ones, a get request, and it's going to be to the job check endpoint, and we know that we're going to use the base URL here. Just going to move this all down a little bit so it doesn't crash, and we're going to set up our credentials again, and this time they're saved, and it's actually a post request, so we need to post the job ID in order to retrieve the details. So we're going to send a body again, and then the value was job ID, and we've got that in the previous node. So we've got post PDF file, and again for good standards we're just going to call it by its actual name rather than Json Dot, and then we can call that job check; post job check. We're going to test that step, and it's going to come back with the status of the file. So it gives us some more details here; it was a success; we got the page count; we got the URL of the file, and you can see that this has now come back with exactly the information we were looking for. It's come back with all of the different supplier details like vendor name, address, contact information, customer, ship to, invoice, payment details—all of the things that we were stripping out ourselves. We've man to get through an external service; orbe it it was probably a little bit more complicated because we were dealing with uploading data, which is never as straightforward as just sending text. And again it comes through at the the same level of detail that we were pulling with our llm node, but the advantage here is we now know how to work with pdf. So that if we wanted to use any of the other functions like converting our PDF to text, we could just go to the end point; we could find the relevant endpoint; just upload again the same URL, and we would receive that response back. So all we need to do is replace that final or this node in here where we post the PDF file to the endpoint; we did; we don't need to replace that node with any of the other functions, and now we've got something that we can plug and play that does everything for our PDFs; we can merge them; we can split them; we can do any of these now because we know how to work with a pdf. API. And given it's one of the more complex API use cases, once you get your head around this, all other API documentation will be really, really easy to to use.

I'm going to show you now how to speed this up even more. Now you know the fundamentals and can Gras that I'm going to show you now how to get there even faster with any API documentation in the HTTP request node. Let's say we want to use the AI invoice passer node again. We're just going to copy that node down here; in fact we will start from scratch and do a HTTP request, and what we will do is we're going to try and replicate this as quickly as possible. So we're going to go to the documentation, and in the documentation we'll go back to our AI invoice passer, and we will scroll down, and what we're looking for is a curl request. So you see this curl here; this is essentially a computer's way to access an API, and it just lays out everything we need in one simple Co request. So all we're going to do is copy that, and you can see it's got all of our headers like content type application Json; it's got a header with a API key; it's got the URL in the body, which is marked with d. So we're going to go back, and very clever trick inside the HT TP request inside n, you've got this import curl. What we do is paste the curl command here, and we import, and that will prefill most of the information. So you can see that the API key has now been added to the header parameters; you can see the endpoint and the method have been changed or updated, and you can see it's prefilled all the Json. Naturally, it's filled out all of the information. So we didn't use a callback URL, so we're going to delete that, and also this UR L is a dud URL that we're going to need to connect to our own URLs. Similarly, putting your header parameter like this directly in the body rather than through the authentication type is not best practice, and actually if you share your Json or your workflow with others they'll be able to see your API key. So I would always recommend setting up authentication properly. We'll go back and just do the generic credential type header o PDF Co; we've already set that up; whoops, and then removing it from the headers there, so we don't need to send any other headers. But effectively we set that up with one Co requests super quick; we don't have to read all the end points and input all the details; we're literally within 30 seconds. We're going to have to update this with the expression, so we will connect it to the previous node, and again we can just come down here, delete that expression, and this was the URL from one of our previous nodes here, and again we're just going to replace that with first, and there we have it—the same node but done in 30 seconds by just getting the color request from the documentation.

An even quicker way when you don't even have access to the API documentation or you can't be bothered to go look at the API documentation: you can go to a service like perplexity, and you could type in okay pdf. Co Co request for AI invoice passer, and that would just search the web for the API documentation and actually come back immediately with this Co request. So without even having to visit the API documentation, you can just type something like this into perplexity, which is a web search engine supported by an llm on the background, and it will give you the colod request straight away. We can copy that, go add that in, and it's also given us some information about optional parameters and response format. So effectively digested all of that documentation in about 5 seconds; we'd have instant access to any API—really, really powerful for business use case. To round up this section, I have gone through and pinned up all the data that we've collected from that so that we can actually uh put the data into our air table and compare it to our own invoice passer. So we built our own invoice passer using an llm, and now we have built an invoice passer that just connects to an API; does exactly the same job; Returns the data for us. So we will put that into our air table. So we're going to copy this node here and paste, and it's common place to copy and paste nodes and then just change the names; change the inputs because it's a lot quicker. We going to post invoices, and we'll just call it API just to distinguish from the one above, but this time we're going to have to map it to the body that's being received from the API API request. So we will now have to remap all these. We're just going to refresh the columns here. We already know we're attached to the right table; the financial table just to remind you has all of these fields. We're just going to um put a dash one on there so that when we go to update the invoice we can see below how the invoice processes um so we're going to go in here; we're going to look inside the body; we're going to grab all of these details and fill them out individually. So you can see it's grabbed invoice number, for example, and as usual we're going to go and we are going to name it rather than refer to Json directly. Great. So I filled out those details now in post invoices API, but you can see that because this is a service where we're not controlling the outputs like we did with our llm, we don't get to pick exactly what Fields they have, so we have to map to those. So we haven't got a field that's generic description um which is a shame, but we've got things like invoice date, payment date, invoice number, total price which comes with the currency attached, the line items, the supply name, and some additional info. So we're missing some of the info that we were able to build through our own llm, but nonetheless it's a really good service that we can use. We're going to test that now and see it go into our table. So that's been added to our table. We'll go back, and we can see these are two the same invoice numbers, but one's got a dash in, so perhaps one is better off picking up dashes, and that's something you might specify in your own bill llm node; make sure to include dashes in invoice numbers, and uh yeah, all of the details seem to be relatively the same, but obviously some of the fields are not filled out in the same way, and even the line items we can compare in here. So actually this one from the apip pdf. picked up more line items in there, and then we've both got uh around payment terms or payment methods here. So yeah, both really good methods, but that was it.

To round up the API Mastery section, you can see how building your own sometimes could be more beneficial because you can choose the structure and tell the prompt for the llm exactly what information you want, but but sometimes it's just easier to connect to an API and actually use an API because now we've set up that API it can continuously run. It took a little bit longer to set up initially because of dealing with all the the data formats, but if you know how to do both methods then you can absolutely choose which one suits you best and decide on a case-by-case basis exactly which one you'd use for what. So if you come back to the canvas and look at what you've built now, we've effectively created three whole automations, getting more complex as we go through. So we've initially created a simple first automation where we've got a file from our Gmail; we've converted the format, and then we've posted that to our email's table in air table. So we've manipulated data and sent that to a table. We've then created an entire end-to-end automation from scratch that includes an llm call in the middle of it as part of a non-agentic workflow, as we discussed earlier, where we take files from our email; we extract data from the files; we know how to format that data in code notes, and then we literally prompts the llm to pull specific information and post that to our database. And then finally, for the third automation you've built from scratch, we've dealt with complex API documentation; you've learned how to read API docs; the core concepts of API documentation and how to do that quickly and efficiently to achieve the same results that we could achieve within llm. These are core skills that you will need when dealing with your business data. So if you've made it this far, really well done. We're going to move on now to scalability. So building workflows in isolation like this is great, but we need to understand how to find the resources to build workflows more quickly, but also how to structure our workflows so they're really scalable, and anyone of our team can come into these workflows and understand exactly what's going on. So that's what we're going to cover now. This is about how to make your life easy and your team's life a lot easier by just implementing some best practice, but also understanding where to get the right resources. You'll notice immediately that actually if we zoom out on this we've got two of almost identical workflows; one is really clear, and the other is not, and I'm wondering if you can spot the difference between those two, and it is the sticky notes. So this may sound obvious, but I've seen a lot of content put out there where people don't properly label their flows. If you were to give this to a client or you were to implement this and give this to a colleague, they would come into here and not be able to understand at all at a high level what's going on in your workflow. If you came into this flow here, you could absolutely at a high level tell me what's going on: we get some sort of file from Gmail; we are doing some sort of data formatting, although we don't know what; we know we're formatting the data in some way; we're then grabbing key data using an llm chain, and then we are outputting that data. So we know at a high level exactly what's going on here, whereas down here we've not labeled as we've gone along. So what we're going to need to do is retrospectively label those in a clear, consistent manner to make sure that when we pass this on to someone else they know exactly what's going on, and more importantly, when you come back to this workflow—which you will come back to this workflow, trust me, I do it.

All the time, I'll go back to my workflows, and I need to see exactly what's going on. I need to isolate a problem or change something in one area, and labeling it makes it really scalable because I can come back and do that very simply, and so can others. So I've labeled up all of those. Now you don't need to label every single thing, but you need to label sections and functions of work. So we've got the inputs here: a file trigger, but also the upload URL. We've got a section here which is about uploading the file to pdf.com Co and returning the output, and then we're outputting data into our dat data table. You can see how that's immediately so much more obvious for both me and anyone else coming to return to this.

The next tip around scalability and making your life easier is just around your workflow naming. So if I go back to my overview here, you can see I've got a lot of workflows. When you get to this point where you've built out as many workflows as I have, it becomes very difficult to navigate through those. I hear rumors that n are finally rolling out a folder structure, so that may come in soon and make it a lot easier. But you also need to name your nodes a sensible name. So you might have a convention like content template admin and then append a name that is about the function that it's actually doing. But something like test workflow demo doesn't actually say anything about the workflow. But when you open up new workflows, it will be called my workflow 1 2 3, and actually when you're trying to navigate back through a lot of projects, it's going to be really difficult to find the right project. The second thing around that is tagging. So you can actually go into the workflow, set up your own tagging system. So maybe you want to tag around uh AI agents, document extraction, error handling—all of these different things that you can decide what you tag around, and you can then filter by your tags and you see, for example, all of those tagged with AI agent.

We spoke briefly about memory issues earlier and running into memory problems on your workflow. n over the last few months improved their canvas so it runs much smoother than it used to. But having multiple workflows on the same canvas generally is bad practice. There's a few reasons for that. The first is the execution log. So you want your execution log to be a history of all executions of one given workflow. If you've got a canvas with multiple workflows, all of these executions are going to be very confusing. When there's an error, you're not going to know which workflow the error is part of. We've just built it like this for ease of visual use, but if you were building production systems, you would actually separate each of these into a new workflow. So with n, you can actually just highlight whatever you want to copy and copy it to a new workflow. So we could copy this here, we could open up a new workflow, and we could paste in these values. So we now have a separate workflow which has a separate unique URL that we can execute separately.

The second reason why this is important is because although these are low memory intensive, if you've got a lot of larger workflows running on one one canvas, then it's going to cause issues with loading and memory, etc., because they're all on the same workflow. So it's a good idea to separate them out completely into separate workflows. It's a bit different here because we've got two workflows which are effectively doing exactly the same thing, just with different ways of doing it: one through an llm, one through the API. But in general, you'd separate these onto separate workflows. The final thing I'll mention around this is around parallel execution. So if you're wondering whether this could also run at the same time as this, yes it can, on the same canvas. However, again, it could cause more issues than you want, so actually you'd probably want to separate these so that if a Gmail came in through here, it would run on a separate canvas and run on a separate canvas for this workflow.

We're going to cover now modular design. So you'd want to design your workflows in a modular fashion so that they can be plug and play, and we can reuse certain core elements again and again. So an example might be this invoice passer that we created. We'll just copy that, and we will go to a new workflow, create a new workflow, we're just going to call it something like invoice passer test for now, and we're going to paste that in here. So there might be occasions where actually we receive invoices both in our email, but we might be getting them through WhatsApp for business if our supplies are on there, we might be getting them through Telegram, we might be uploading them directly to Google Drive. So in that case, we might need to use this pre-processing stage and the extract key info and post invoices again and again. So we have options here: we could copy and paste this down here, and we'll change the trigger. So we'll now have a WhatsApp for business trigger on message. So we're going to find that trigger and put that in, and then we also said we might have a G Drive upload. So we're going to change the trigger; we'll go G Drive trigger on changes to a specific file or folder—that should have been folder—and then we'll attach that. So you can see that that would work right: we have multiple inputs that go through the same flow. But what if we wanted to change the prompt? We'd have to come into basic llm chain one or two, basic llm chain, basic llm chain one. So we'd have to update in three places if we wanted to do that.

An alternative is to actually just attach this trigger directly to the flow. So we can now get rid of of all these bits—let me just move that—get rid of all that, and we can actually attach multiple triggers that connect to the same flow. That is an option. We might have slightly different processing, but we could standardize that with a set node in the middle. I just realized here we had not reconnected the loop, which we should have done. So we can connect multiple triggers, and that's absolutely fine. But maybe there's some standard processing that we do to Gmail, and there's some standard processing that we do to WhatsApp, and there's some standard processing that we do to a G drive. So we might have this data processing stage like this—let's just say data processing, and we'll ignore what we want to do for now, it's just the concept that's important—and we'll copy that, and we have separate rules for data processing for WhatsApp and separate rules for data processing for G drive. So we could absolutely do that where we've got this separate data processing rules for each method. But what about if in other flows we're also going to take in a Google Mail, taking a WhatsApp message, taking a Google Drive, and we're going to do exactly the same processing again? Well, in that case, why don't we entirely split out just the triggers here and the data processing, and we can do that in n, and it's really simple, and it makes for really modular designs. So if we break the connections here, we now know we need to call this workflow from other workflows. So to do that, we just use our execute sub-workflow trigger, and what we're doing is saying that this workflow, the invoice passer test, can be called by another workflow. So what we might have is okay, let's separate these into completely separate trigger workflows that just do the data processing. So we'll have one for Gmail, and you might not structure it in this way, but the whole point is around modularity, and anything you're going to reuse you should actually just uh only change in one place, and that's really important from a reusability perspective and will save you a lot of time. So what we'd connect to the end of this perhaps is an execute sub-workflow node, and we can choose our workflow which was invoice passer test. Now whenever this runs, it will execute our sub-workflow.

So if we test this workflow here and we go back and fix the issues that were in the invoice passer test and we change this input data mode to accept all data, you can also define the fields that are going to be passed in if we only want to pass some in or define it using JSON, but let's accept all data for now, so it's ready to accept data. We'll go back to our Gmail trigger, and if we now test that, that will pass through, and it will start executing our other workflow, and you see this one continues to execute until it's received a response to say that this is fully completed, and it's now returned, turned the end of that sub-workflow. So from this Gmail trigger workflow, we've managed to trigger our invoice passer, run it, wait for it to respond, and then take the response at the end. You can see how that then creates reusable blocks. So say we wanted to reuse that core set of functionality again and again, we could just call it from other workflows. The same with having multiple triggers, we could just set up multiple triggers that have different data extraction or data formatting and then execute a certain workflow inside this sub-workflow. You can actually see we can see that that's been executed. If we go back to our other workflow, we'll also be able to see it in the execution log. So that has just run with our inputs that have come through, the binary files that have come through from the other trigger. So what we might do then is set up another input and keep this part of the functionality exactly the same, but change the inputs that we're passing in here. So that is how to create modular workflows, and I'm sure your imagination is running wild with the possibilities of creating reusable workflows with this structure. It's a tremendously helpful set of nodes when you're working across multiple clients and you just need a core set of reusable functionality.

It would not be a good workflow-ation for business course if we didn't touch on error handling and how we tackle that. So there's a few built-in features that you must know about when it comes to error handling in N. Inside each node there are settings. Um, we've covered this at the start of the course, so I won't dwell on it too much, but you can ask it to retry on fail. We've then got the different options for on error, and most of the time what we want to do is pass the extra item to an error output. What we can then do is if we open up the tools, we can get it to throw an error, and if we connect the error to that, what that enables us to do is give a custom error message. So if the post invoices fails, we'll say error inputting into air table. So that when we get our error notification, we will get that error message, and it'll be more readable than then post invoices and then a long code. So that is the first thing: implementing just some error handling on a node by node basis. Some nodes you might want it to continue on error; some you might want it to stop the workflow. The second is around the settings for workflows itself. So if you come into the settings, what you can do is set up a few standard things like time zone, whether you want it to save your production execution—so anything that's not a test, when you're in here testing, a workflow is a production execution when we are active in the button up there—whether we want to save our failed ones, which you usually do, whether we want to save our production ones, our successful ones, depends on your memory. If you don't have a huge amount of memory, you probably don't want to save your successful production executions if it's executing every minute, for example. Save our manual executions; we'll always have that as save because we want to see our tests, and then save execution progress—up to you. There's also this timeout after, and I tend to set it to 3 to 5 minutes, but when you're dealing with complex llm or AI agent workflows, you probably want to set this um, you know, 10, 15, whatever you feel necessary based on your testing. It will just time out and stop the execution if it reaches that limit. But something like this where it's an invoice passing, we're dealing with document data, so maybe five minutes, but at a push it should be one minute, you know. So those are the uh settings.

The other thing that I'd advocate for you to do is to set up an error handler that by default um throws all of your errors to a certain place. So I've got one in here which I'll share in the community, which is an attaching a default error handling flow to every workflow. So if I've not gone into the settings and put in this error workflow as the default error workflow, then it will go through all of my n flows that are active and set this as the default error workflow. What that does is it forces it to run this workflow when an error actually occurs, and what that does is trigger this error trigger down here, and you can set this up to do various things. For me, whenever one of my workflow errors, it sends me a Telegram message, and that Telegram message has the workflow name, the node which failed, the error message, and a link so I can go directly to that workflow. So just a super helpful thing when you're setting this up for clients or your own business; you absolutely want to know which ones are erroring without having to go to the logs yourself. You can send it by email, WhatsApp, whatever you want, but the point is you have one default way to handle errors for all workflows, and then to set that up we just go to the settings and assign that as our default error handling workflow, and now as soon as it errors that will cause that workflow to contact me by Telegram.

Debugging in the workflow: so you see if we come into the executions, we can see these failed error logs, and if you go into the node, you can see that this data was passed through and it failed at this point. That's really difficult then to go back to the editor and try and replicate that. So n and have this built-in feature called debugging editor, and what we'll do is click that, and it will push us to push the data and pin the data back to the workflow in the editor so we can replicate exactly what happened there and try and fix it directly from our workflow. Now to get this, you need to make sure you've registered your community edition. So if you come down here to settings and you go to usage and plan, it will effectively prompt you to register your community edition. Once you've done that, activate your key that's sent to your email, and you get a few features including the debug in editor for free.

Talking of community, the Nan Community is a really great asset, and you should definitely leverage what's out there in terms of resources. So we're going to cover the basics of that, and trust me, this is is so important; you will use these things again and again. The first are Community nodes. So if you have the self-hosted version, you'll be able to get these Community nodes. You can go down here, go to settings, and in settings will be Community nodes feature. You will see that I have a lot of these Community nodes: one for appify, one for browser lists, 11 Labs. There's loads on the market that you can install. You go to install, and you can go to npm, which is effectively a marketplace for different JavaScript packages, and you'll be able to see all of the N Community node packages. A community node package is essentially just a node like air table, like Google Cloud, that na hasn't made native to n software, but somebody in the community's decided to build those. So, for example, 11 Labs is a really good example. Deep seek, before it became a node, was an example. However, it's not great to search on npmjs, but this is why the community is even better: there is somebody in the community that's really active that has created a much easier search functionality for Nan Community nodes. It's at n-community-nodes.octo oicc, and this just makes it super easy to search rather than the clunky method. So we can type in YouTube; there's one for YouTube transcription, there's one for YouTube info. If we go 11 Labs, you can see it gives you information about what the node does, when it was last maintained, how many downloads per month, and we can click on that, and it will link us directly to the page. And within the page, you will see that it has a name like this: na an noes 11 labs, and what we can do is go back to our Edition here, and we would just put in the name that we want to install here. I've already got this one installed, so it's going to uh tell me that we can't install it, but it would then install it on your system. If we go back into our workflow, open up the nodes here, if I search for 11 Labs, you can see it's been added, and it's also got this cube next to it which signifies that is a community node. So we can open that up, and you can see they are as detailed as the normal nodes. Somebody has created all of these actions within that node. We can open that; it looks exactly like a normal node, but it's maintained and built by the community.

Now imagine you're building out a workflow for your business and you want to post content to social media, and imagine building that from scratch every time. You can absolutely do that, but you've got to leverage the n pre-built Community templates or workflows. So you can see on n.w workflows, they've got 1,325 workflow automation templates that you can leverage that are kept up to date. So if we click on AI here, we've got as recent as they're basically updated every week. So we've got one here that's paid; we've got multiple here that are free; most of them are free. And if, for example, you wanted one for posting to Twitter or X, we just type in TT Twitter, we'd search for that, and we've got one here: AI powered social media amplifier, automatically promote your YouTube video on X, post new YouTube videos to X, spreadsheet to tweet automation. So you can see how these are super easy. And if we just grab one that's free here, if you come into the template, it will tell you the title of the template, what nodes are used in the template, who's created it, and you can go on their create a profile; you can see what other workflow templates they've created, and then you can see some information around how it works, what the requirements are, and how to set it up. All of these have a base level requirement of telling you how to set this up. You can see that this has got a bunch of different nodes; we can zoom in and see the nodes, and then we can even open the nodes directly if we double click into them. Now there are several ways to get this into your na environment. The first is literally just highlighting them and copying, and if we go back into our environment, we can literally copy it below if we click on the canvas, and it will put in that workflow directly there. So we don't even need to leave or download anything to put it inside. But we're going to go back, and there are other ways to use the workflow. We can import it directly into our self-hosted instance if it's connected; we can copy it to clipboard, which is exactly the same of what I've just done; or or if somebody sends us a file, a JSON file, then we can just go into our workflow and import from file and import a JSON file directly, and that will open up in the canvas. So lots of different ways to do that. Definitely go out and check the templates Library; it's one of the best things about n.

Being on the sustainable use license means everyone is really friendly and sharing all their templates at all times. Getting help: so you'll be building your workflows for your business or for other businesses, and you will hit issues. There's no doubt it's like uh when you start a new skill; you're always going to come along issues that you've never seen before. There are two resources I recommend for this. The first is the n community: community.n.o. The community has lots of different uh posts that might cover your previous issues, so you can just search SE in here. Say you've got a Gmail issue; there'll be lots of suggested posts that you can go and review previous comments about. They also give their announcements on here for new updates to the software, so you can come here; they have tutorials; they have lots of helpful resources, and everyone's super nice and super helpful in this community, and they will uh come and answer your questions. You can see the activity is all within the last couple of hours, so everyone is really active on this community. The second resource that I definitely recommend is signing up to perplexity.doai. They do free accounts; it's effectively web search with an llm in the back end. So it can connect to all of the latest documentation for n, and we can ask it like uh what are the latest n updates. So if you're troubleshooting, this is a really good step. You can literally paste the JSON values or paste uh content from your prompt in here and ask it, give it some context, ask it to um help you out with a specific error code; copy and paste the error code in here, and this will get you 90% of the way um it's a really helpful tool. You can see what are the latest updates; it's come back with the latest version released on Feb the 6th, and it's now Feb the 19th. If you have an error code, paste it in here; I guarantee it will get you most the way there. Things like code nodes are really helpful to iteratively build with perplexity, by the way, in the background to perplexity; you can choose the different models. So if you want some more deep research models like R1 or reasoning O3 mini R1 deep research, etc., then you can access those, but it runs with things like Claude 3.5, Sonet, GPT 40 mini in the background anyway. So it just powers up your searches with webs.

After building hundreds of workflow automations for clients and all sorts of businesses, I decided to create this community and shortcut the path to AI agents and workflows for you. Whether you're a business owner, a content creator, or someone who wants to build a business around AI agents and automation, then this community is designed for you to get started as simply and as quickly as possible. When you join in the community, you'll find this start here post. You can start here, introduce yourself, share what mission you're on and your business goals, and you'll get connected to like-minded people on the same Mission as you, with similar values from all over the world. So Roberto here, for example, has 25 years of automation knowledge as a controls engineer, and his goal is to create an agency using these automations. Sahill has been running running an agency for a year now and been working with AI for roughly 2 years now, and he's got a London-based agency and wants to connect with like-minded people similar to you. And then Mary here has got a fascinating background; she's living in Cape Town, and she was a software tester for 20 years, but since the AI Buzz has started, she's decided to dive right in with this community and learn how she can automate her own business. But besides that, she's also a trained life coach and always looking for ways to build out that work and her coaching. Then if you head into the classroom, you'll find a bunch of free courses that will take you from beginner to AI expert. Each of these courses is broken down into the Core Concepts to help make it more digestible and easier to mark where you've got to. Here I share all all my top tips on what I've learned in how to shortcut my journey to Mastery of N and workflows. If you're not looking to learn from scratch, then we also have pre-built templates just for you in our template Library. These are all production-grade templates, having worked with a ton of clients and built over 100 workflows now. We've got some great examples of business use cases in here, including AI agents that help us manage our invoices, manage our email inbox, complete our research, scrape any website—a ton of business use cases that I've earned thousands of dollars building out for my clients. And if you still have any

Problems? Then you can just head to the questions section within the community, and we'll tackle it directly in the community or on a call with you.

I hope you learned a lot from this course. Thanks so much for watching. Check out my other content and hit like and subscribe if you want to see more.