How to use Loop on items?

I would like to overcome the limit of 30 days max for a Delay step. So I check the date difference and if it is less than 1 month I proceed, otherwise I wait some days and check again the date difference.

To do that I decided to use loop on items, but I do not know how to tell it to start over from the second step of my flow. The error it gives is:

"\"{\\\"message\\\":\\\"The items you have selected must be a list.\\\"}\""

How do I solve? My goal is to check if the date difference is less than 30 days and if yes go on with the steps, otherwise wait a bit and try again.

So the step n.10 should go back to step n.2

Instead of a loop, you can add a HTTP call after the delay maybe to call the same webhook?

maybe, but I wanted to understand how loop piece works

You only have 2 options as far as I know.

  1. My first suggestion to call the webhook and pass the date that you’re trying to compare with. You don’t need the loop for this. Webhook → Check condition → Delay → Call itself via webhook.
  2. This is probably what you’re attempting. Create a x amount of list items and do a loop, bring your step 2 and all other items within that loop. You will need to break out of this loop if it meets the condition, otherwise, it will keep repeating the same nodes over x times.
    You will need either a while loop or break within a loop which AP neither supports at the moment. If you really want to make this work, you will have to set a flag in the storage to stop processing once its been processed once.

@jero,

The error indicates that the value needing to be passed to the loop needs to be in a list format.

I assume from the screenshot which shows you are passing step_3, that this only contains a single value, as it is returning the current date.

If you are looking to fetch multiple dates for multiple entries, you would need to loop prior to storing the dates fetched.


Question:

Is there any reason you need the trigger to be a webhook?

I only ask because, in my personal opinion, you might be better off swapping that out for a Schedule Trigger. This would allow the task to repeat while published, as it will come back and check by your desired schedule (e.g., every X minutes, X hours, X days, X weeks, and so on, or even set a Cron Expression).

For me to achieve what you are doing, (I would probably use a code piece to handle most of the date-checking logic), but if you want to achieve it using the steps in a flow, you could try the following:

  1. I would keep your Get Current Date as is
  2. I would also add a Add/Subtract Time piece which will take the result of the Get Current Date and add 30 days to the value.
  3. Then, I would completely remove the Date Difference, as I wouldn’t really need it anymore.
  4. Next in the Router, I would simply check If currentDate + 30 Days is Equal to the currentDate. If it is, then it will follow the steps under the TRUE branch, and if it isn’t, the flow will follow the FALSE branch and do nothing (as long as you remove the pieces you have there now).

If it helps, here is a Demo of the flow in action:

Currently, if you test the flow, it will return the FALSE branch (because, of course, today’s date + 30 days is obviously not equal to today’s date).

But, if you want to verify that it does trigger the TRUE branch when met, you can simply swap out the value in the Router Branch to the result from Get Current Date instead:

Then, you will see it triggers the TRUE branch.

I have added a couple of console.logs() as well as output the result as a string inside of custom code pieces (which you can view by clicking the last step of the flow after running the test flow). Once it has run, you should see the following results:

  • If TRUE, you will get: The date is more than 30 days old.
  • If FALSE, you will get: The date is less than 30 days old.

Important Note: This does not handle checking for if the date is past the 30 days, and so if the date is NOT EQUAL to the current date, it will fail and you will get the FALSE branch. But it works on the assumption, that you are checking the value each and every day, so there will come a point when the 2 dates are equal, so theoretically, it should equal TRUE at some point. (I could not see a Date/Time Option for the Branch Comparison that checks for Greater Than or Equal To, which is why I chose for If it is EQUAL. Another reason, I would probably just handle the checking in a custom code piece).

Hopefully, this helps. But this assumes that you don’t need the trigger to be a Webhook or that you don’t need to iterate over multiple values. If you do need to loop over multiple values, then this might not be very helpful at all, as you will need to add the loop pieces to go over the multiple values.

EDIT:

I did mean to point out that if you decide to go with the Schedule Trigger, it would actually eliminate the need for much of the checking process above.

You could simply set the schedule to run every 30 days and have it run the flow with no additional checking needed. This is because it will only run every 30 days, making the date 30 days or older, which, of course, meets the required time to have passed.

1 Like

Hi GunnerJnr, I appreciate your detailed response.

My trigger needs to be a webhook because it listens to a third-party event service. When a new event is booked the webhook gets triggered and among the data it gets there is also the EVENT-DATE.

I get this date and use that in my computations.

You may ask why I am building this workflow. Well the reason is that the third-party service only has a ORDER-CREATED webhook trigger, hence I use that to get my info about the attendees and the event start date.

My goal is to send an automatic email as soon as the event ends. I can’t do that in the third-party service, and they do not have a webhook which listens to EVENT-ENDED, so I have to find a way.

The only solution I found is to get the EVENT-DATE with the webhook I have, which gets triggered every time a new order for that event is created (a ticket is booked). And from there, as orders can appear well before 1 months or 2, I have to overcome the limit of delay limited to 30 days.

As I am writing to you right now I got another idea, such as storing all the orders in a baserow table and with another flow process them. I have to experiment, if you have other ideas please tell.

As far as I understand the loop item does not loop on previous steps, it wants a list, but which list? Is there an example somewhere of the loop element?

Morning @jero,

Unfortunately, I don’t have any data to test with from a webhook handy. So I am just using the webhook /test URL, and I have appending a query to the end (which is todays date (whoops - I just realised I put 2024 :sweat_smile: - living in the past, haha)) for my test data. this is what the URL looks like in full:

https://cloud.activepieces.com/api/v1/webhooks/WEBHOOK_ID/test?date=18/03/2024

This allows me to be able to use the test data from this made up query to mimic as if it was data being sent from an actual webhook.

Note: I replaced my actual webhook ID with the text WEBHOOK_ID so you would need to update this to your ID if you wanted to use it. But since you are working with a live webhook, there shouldn’t be any need for you to use this.

Next, you can use a custom code piece to trick ActivePieces into returning the data as a list, (even if it only has a single item). You will need to make sure to fill in the Inputs with the data you want to pass.

In my example below, you can see I pass the query from my made up webhook test data:

And, then you can use something like this in the code piece to achieve your desired result.

In this example, we take the input data, make sure even if it is a single result, that we always return it in an array format (which will meet the ‘list’ requirement needed for the loop piece).

I have added comments to explain what each part of the code does:

export const code = async (inputs) => {
  // This will store the data you have passed from your webhook from the "Inputs" above.
  let data = inputs.webhookData;
  // Now we need to make sure it's always treated as list for the loop [technically, an array].
  if (!Array.isArray(data)) {
    data = [data];
  }
  // Then we will extract the 'date' field as a plain text string (for storing in our table, storage piece, or whatever).
  const formattedData = data.map(item => item.date);
  // Finally, we return our formatted data.
  return formattedData;
};

If all went well, we should now see something like the following:

Now, we can utilise the result in our LOOP piece. In this simple example, I just use a Table piece and use the Create a new entry inside of the table.

As can be seen below:

Here is a link to the demo flow from the screenshots above. It isn’t fully what you wanted with the Router piece incorporated. Unfortunately, I am out of time and need to head to work.

But this should help you to fill in the missing parts of your flow in the original post, and help you to find a working solution.

Hope this helps. :blush:

EDIT:

Forgot to mention, don’t forget you will need to create the Table “Event Date” to use in the table piece.

Also, if you just wanted a very simple example of the loop piece in action, I did create another demo, which I wasn’t going to share, but hey, it might help others, so why not. (Just note, that to use you will need to create a table named “Colours”):

1 Like

Oh now I get it, the Loop item takes a bunch of items in an array and executes the steps inside for each of those.

I truly appreciate your perfect explanation with example, I now know more of ActivePieces! However it seems like it is not what I am looking for.

I am looking for doing this:

I am supposing I don’t have to use loop on items, instead I have to use sub-flow linking maybe?

@jero,

Might be easier just to change to a scheduled flow (like yesterdays example) and move the webhook one response down, then you can keep checking the date on a schedule?

But how can I get the new ticket orders via webhook? New orders arrive randomly, and webhook for new orders has to be triggered every time a new order arrives.

@jero

Oh yes, sorry, dumb moment. One possibility might be to create a new flow that has a schedule trigger, then call a sub flow, so it runs the flow with your webhook?

I am a little busy right now, but I will have a think later, and see if there is a solution.

Thanks.

1 Like

@jero

Another option, just while it is in my head so I don’t forget, is to create one flow that just has the webhook and saves the entries to a table.

Then create another flow that uses a schedule as the trigger to pull the data from the table and check if the date is older than 30 days. If so, send an email. If false, because the flow is on a schedule, it will keep checking until it is true.

Anyway, as I said, I will think about it later.


This is my updated reply after a lot of thinking; I apologise in advance for the lengthy reply.

@jero

The way I see it is that I only see two possible options from here:

1. Add additional delay steps, as I noted it states on the step itself:

Note: The maximum duration per step is 30 days.

So theoretically, this would allow you to overcome the 30-day max period, although I am unsure if this is even allowed, frowned upon, will actually work, or is even a viable solution. Not to mention that it wouldn’t really be of much use to you anyway, as ultimately, you cannot restart/re-trigger the flow to be able to then run the conditional logic again!

I did think about suggesting that you add more branches (nest) inside of the FALSE branch, which would allow you to make additional decisions based on newer logic. I am not sure if you are aware that you can do this; see the links below for further info:

But again, I can’t see how these will help, as you want to restart the flow!

:thinking::thinking::thinking:

The other thing bothering me, and I am trying to understand it, is that you mentioned that each time an event is booked, it triggers the webhook with the event date.

So can I ask, if this is the case, then how would you be able to go back and check a prior booking after a delay? Surely, as soon as a second booking happens and the webhook is triggered, the first date will be wiped out by the new value, as in your current flow, I cannot see it being stored anywhere.

2. The most viable solution I can think of right now is to create two separate flows. (Think of them like one flow, but split into two parts).

The first flow can go one of two ways:

  • a) The first approach will simply have your webhook trigger and a table or storage piece (or, of course, if you prefer, a Google sheet, notion, airtable, or whatever) to store the data from the webhook into a table.

  • b) The second approach is a little more like what you have now, but instead of using the delay piece, if the date equates to FALSE, swap this out for a table piece to store the data of only the dates that are not older than 30 days.

Note: As I don’t know what data you are working with, it is hard to give a full solution. You may very well need multiple columns.

For Example:

customer_email, booking_id, event_date

Example Table:

Customer Email Booking ID Event Date
john.doe@email.com 12345 18/03/2025
jane.smith@email.com 67890 22/06/2025
mark.jones@email.com 54321 05/11/2025

Note: You could even take this a step further and have event_start_date, event_end_date, etc. This would allow for easier conditional checking down the line to determine if the date is older than 30 days. (But for now, I will leave that up to you so I can keep this example simplified.)

Extra Note: Taking approach b) would allow you to instantly send an email to any booking where the end date condition has been met (is TRUE) and then store the dates where the condition hasn’t been met (is FALSE) for a later check in the separate flow, which we will touch on below.

So, in the second flow, you could start with a Scheduled trigger, which will allow you to set the flow to run every X number of days.

Similar to the first flow above (but now without the need for the webhook trigger), you can now simply fetch your data from the table to automatically compare the dates for the date checking to determine whether or not to send an email (for this step, you could actually utilise the loop piece to iterate through each entry in the table).

Then, as before, re-use your router piece to send the email if the condition is TRUE.

Important: Here, I would also add some step after sending the email to remove that entry from the table, just to make sure that it won’t be sent again the next time the scheduled flow runs.

Note: If you wanted to complicate things, you could, in theory, add a new column that has 'success', 'sent', or some other flag, then add extra conditional checks to the router step so that the next time the scheduled flow runs, it knows to ignore those entries in the table as they have already had their email sent out. But it seems a bit overly complex and unnecessary, so it would just be easier to remove the entry entirely after the email has been sent).

If it equates to FALSE, then do nothing (so just leave it blank with no steps; then, when it re-runs again the next time, at some point, the condition will eventually become true, and the email will be sent out).


Optional Approach:

As we mentioned earlier, it is worth noting you could replace the scheduled approach with the sub-flow approach. This would allow you to call on one of the flows from the other, but as far as I know, as stated in the documentation on it:

With the SubFlows piece, we’ve made calling additional flows as simple as selecting an option from a dropdown menu. Whether you want to wait for the subflow’s response and act based on that or simply call the subflow without waiting for a response, the SubFlows piece gives you the flexibility to do either.

To ensure ease of use, the only subflows that will appear in the dropdown menu are those that meet two conditions:

  1. The subflow must have a “Callable Flow” trigger.
  2. The subflow must be published.

This ensures users are only selecting valid subflows, keeping the process intuitive and hassle-free.

Documentation Links:

So you would need to utilise one of the triggers for the Sub Flow piece.

So my thinking here was to take the same approach as the above, but rather than using the schedule, you can now add a step to call on the second sub flow to pull the data from the tables and check it.

The only downside to this approach would be that it would only get triggered each time a new booking happens when the webhook is called, so it might not be the best option if you don’t get a booking for 90+ days, that means any of the entries in the table, won’t get checked for those 90+ days either.

Which is why, I decided on it being a secondary solution.

Hopefully, this will help you in some way to achieve what you are trying to achieve. Or even spark that “A-ha” moment, and you will come up with something that works for you.

I guess this could be a good next step for ActivePieces (@Abdul): incorporating a way in AP for users to retrigger an entire flow from inside a step, like for your needed use case above. (Maybe it is already possible, and I just don’t know about it.)

Kind regards,

1 Like

Yeah this came to my mind also while I was explaining the actual flow. Indeed storing the data in a table seems necessary.

Exactly what I also ended up thinking.

This is clever, but I don’t mind storing the data for all events & orders anyway. My events are not huge so only 20-60 participants are there in an event.

I am evaluating to create a scheduled trigger to check every day if TODAY is the same day of the date EVENT-ENDED and if TRUE then send email. I will look into it, and in the meantime I asked to implement the ticketing platform in question to ActivePieces. It is already present in Zapier but very limited.

You can read more here: https://activepieces.featurebase.app/p/tickettailor
This will enable me to use different parameters instead of the one provided via webhooks. So in a way or another (with webhooks or native integration) I feel it is doable!

I appreciate your help and I hope ActivePieces will be famous at least as Zapier or even more!

1 Like

Sounds like an excellent plan, and would definitely help you to simplify things moving forward.

You are welcome, and I couldn’t agree more. Let’s hope the team gets the recognition they deserve for an awesome product.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.