For Zoho services only


I'm currently part of a wider delivery team at Ascent Business Solutions, recognised as a leading Zoho Premium Solutions Partner in the United Kingdom.

Ascent Business Solutions support organisations with everything from targeted technical fixes through to full Zoho CRM implementations and long-term platform adoption. Working as a team rather than a one-person consultancy allows projects to move forward consistently, with access to the right skills at each stage.

The team I manage specialises in API integrations between Zoho and third-party finance and commerce platforms such as Xero, Shopify, WooCommerce, and eBay. Much of our work involves solving integration challenges that fall outside standard documentation, supporting new ideas, new sectors, and evolving business models.

Success is measured through practical outcomes and return on investment, ranging from scaling small operations into high-turnover businesses to delivering rapid gains through online payments, automation, and streamlined digital workflows.

If you are looking for structured Zoho expertise backed by an established consultancy, you can contact Ascent Business Solutions on 0121 392 8140 (UK), email info@ascentbusiness.co.uk, or visit https://www.ascentbusiness.co.uk.
Zoho Projects: Get All Events

Zoho Projects: Get All Events

What?
A quick article because I couldn't find anything that documented this with a working example.

Why?
The use-case here is that we want to make a ZohoCreator page display events for this month from ZohoProjects.

How?
The bit that stumped me was making a call to the Events endpoint as it would just come back with a blank response...

The reason it was blank was due to my parameters; the key item to remember is that status is a mandatory field and it can either be "closed" or "open". If you have used ZohoCRM then this is obvious; if you haven't then it may be difficult to work this out. Put simply, "Closed" are events in the past and "Open" are events in the future. The "is_open" in tasks is misleading and cannot be used in the request for events. There are hardly any parameters you can send to. Here's some code to get the last 50 events:
copyraw
//
// ***********************************
// get Zoho Projects information
v_BaseURL = "https://projectsapi.zoho.com";
v_Heading = "";
//
// get all portals
v_EndpointPortals = v_BaseURL + "/restapi/portals/";
r_Portals = invokeUrl
[
	url: v_EndpointPortals
	type: GET
	connection: "my_projects_connection"
];
info r_Portals;
//
// once we check the JSON, we can select a portal name and ID, this avoids the need of using up an API request to get the portal
v_PortalName = "my_portal";
v_PortalID = "789456123";
//
// get all projects
v_EndpointProjects = v_BaseURL + "/restapi/portal/" + v_PortalID + "/projects/";
r_Projects = invokeUrl
[
	url: v_EndpointProjects
	type: GET
	connection: "my_projects_connection"
];	
//
// already decided as we only want one
v_ProjectName = "My Project Board";
v_ProjectID = "1234567000001234567";
//
// get all users (optional here)
v_EndpointUsers = v_BaseURL + "/restapi/portal/" + v_PortalID + "/projects/" + v_ProjectID + "/users/";
r_Users = invokeurl
[
	url :v_EndpointUsers
	type :GET
	connection:"my_projects_connection"
];
//
// get all events
// NB: status=open are upcoming events; status=closed are events in the past; status is a mandatory field
// NB: range is an integer and the number of records to return (default=100; max=200)
// NB: index is an integer and is the offset or starting index (not the ID of the record)
m_Params = Map();
m_Params.put("range",50);
m_Params.put("status","closed");
v_EndpointEvents = v_BaseURL + "/restapi/portal/" + v_PortalID + "/projects/" + v_ProjectID + "/events/";
r_PastEvents = invokeurl
[
	url :v_EndpointEvents
	type :GET
	parameters:m_Params
	connection:"my_projects_connection"
];
l_PastEvents = ifnull(r_PastEvents.get("events"),List());
for each  m_PastEvent in l_PastEvents
{
	//
	// convert a Zoho Project DateTime to a DateTime datatype (given 12/12/2023 12:00:00 PM... remove ambiguity: mm/dd or dd/mm?)
	if(!isNull(m_PastEvent.get("scheduled_on")))
	{
		if(m_PastEvent.get("scheduled_on").contains(" "))
		{
			l_ThisDateTimeEventParts = m_PastEvent.get("scheduled_on").toList(" ");
			if(l_ThisDateTimeEventParts.get(0).contains("/"))
			{
				l_ThisDateEventParts = l_ThisDateTimeEventParts.get(0).toList("/");
				v_ThisDateEvent_Year = l_ThisDateEventParts.get(2);
				v_ThisDateEvent_Month = l_ThisDateEventParts.get(1);
				v_ThisDateEvent_Day = l_ThisDateEventParts.get(0);
				l_ThisTimeEventParts = l_ThisDateTimeEventParts.get(1).toList(":");
				v_ThisDateEvent_Minute = l_ThisTimeEventParts.get(1);
				v_ThisDateEvent_Hour = l_ThisTimeEventParts.get(0);
				//
				// convert 12-hour to 24-hour
				v_ThisDateEvent_Hour = if(l_ThisDateTimeEventParts.get(2)=="PM", v_ThisDateEvent_Hour.toLong() + 12, v_ThisDateEvent_Hour);
				v_ThisDateEvent_Hour = if(v_ThisDateEvent_Hour.toLong()==24, "12", v_ThisDateEvent_Hour);
				//
				v_ThisEventDate = v_ThisDateEvent_Year + "-" + v_ThisDateEvent_Month + "-" + v_ThisDateEvent_Day;
				v_ThisEventDateSort = v_ThisDateEvent_Year.toString() + v_ThisDateEvent_Month.toString() + v_ThisDateEvent_Day.toString() + v_ThisDateEvent_Hour.toString() + v_ThisDateEvent_Minute.toString() + ifnull(m_PastEvent.get("title"),"?").trim().toLowerCase();
				v_ThisEventStart = v_ThisDateEvent_Year + "-" + v_ThisDateEvent_Month + "-" + v_ThisDateEvent_Day + " " + v_ThisDateEvent_Hour + ":" + v_ThisDateEvent_Minute + ":00";
				//
				// date and time obtained... do your other stuff here
			}
		}
	}
}
//
// get all future events
// NB: status=open are upcoming events; status=closed are events in the past; status is a mandatory field
// NB: range is an integer and the number of records to return (default=100; max=200)
// NB: index is an integer and is the offset or starting index (not the ID of the record)
m_Params = Map();
m_Params.put("range",50);
m_Params.put("status","open");
v_EndpointEvents = v_BaseURL + "/restapi/portal/" + v_PortalID + "/projects/" + v_ProjectID + "/events/";
r_FutureEvents = invokeurl
[
	url :v_EndpointEvents
	type :GET
	parameters:m_Params
	connection:"my_projects_connection"
];
l_FutureEvents = ifnull(r_FutureEvents.get("events"),List());
  1.  // 
  2.  // *********************************** 
  3.  // get Zoho Projects information 
  4.  v_BaseURL = "https://projectsapi.zoho.com"
  5.  v_Heading = ""
  6.  // 
  7.  // get all portals 
  8.  v_EndpointPortals = v_BaseURL + "/restapi/portals/"
  9.  r_Portals = invokeUrl 
  10.  [ 
  11.      url: v_EndpointPortals 
  12.      type: GET 
  13.      connection: "my_projects_connection" 
  14.  ]
  15.  info r_Portals; 
  16.  // 
  17.  // once we check the JSON, we can select a portal name and ID, this avoids the need of using up an API request to get the portal 
  18.  v_PortalName = "my_portal"
  19.  v_PortalID = "789456123"
  20.  // 
  21.  // get all projects 
  22.  v_EndpointProjects = v_BaseURL + "/restapi/portal/" + v_PortalID + "/projects/"
  23.  r_Projects = invokeUrl 
  24.  [ 
  25.      url: v_EndpointProjects 
  26.      type: GET 
  27.      connection: "my_projects_connection" 
  28.  ]
  29.  // 
  30.  // already decided as we only want one 
  31.  v_ProjectName = "My Project Board"
  32.  v_ProjectID = "1234567000001234567"
  33.  // 
  34.  // get all users (optional here) 
  35.  v_EndpointUsers = v_BaseURL + "/restapi/portal/" + v_PortalID + "/projects/" + v_ProjectID + "/users/"
  36.  r_Users = invokeurl 
  37.  [ 
  38.      url :v_EndpointUsers 
  39.      type :GET 
  40.      connection:"my_projects_connection" 
  41.  ]
  42.  // 
  43.  // get all events 
  44.  // NB: status=open are upcoming events; status=closed are events in the past; status is a mandatory field 
  45.  // NB: range is an integer and the number of records to return (default=100; max=200) 
  46.  // NB: index is an integer and is the offset or starting index (not the ID of the record) 
  47.  m_Params = Map()
  48.  m_Params.put("range",50)
  49.  m_Params.put("status","closed")
  50.  v_EndpointEvents = v_BaseURL + "/restapi/portal/" + v_PortalID + "/projects/" + v_ProjectID + "/events/"
  51.  r_PastEvents = invokeurl 
  52.  [ 
  53.      url :v_EndpointEvents 
  54.      type :GET 
  55.      parameters:m_Params 
  56.      connection:"my_projects_connection" 
  57.  ]
  58.  l_PastEvents = ifnull(r_PastEvents.get("events"),List())
  59.  for each  m_PastEvent in l_PastEvents 
  60.  { 
  61.      // 
  62.      // convert a Zoho Project DateTime to a DateTime datatype (given 12/12/2023 12:00:00 PM... remove ambiguity: mm/dd or dd/mm?) 
  63.      if(!isNull(m_PastEvent.get("scheduled_on"))) 
  64.      { 
  65.          if(m_PastEvent.get("scheduled_on").contains(" ")) 
  66.          { 
  67.              l_ThisDateTimeEventParts = m_PastEvent.get("scheduled_on").toList(" ")
  68.              if(l_ThisDateTimeEventParts.get(0).contains("/")) 
  69.              { 
  70.                  l_ThisDateEventParts = l_ThisDateTimeEventParts.get(0).toList("/")
  71.                  v_ThisDateEvent_Year = l_ThisDateEventParts.get(2)
  72.                  v_ThisDateEvent_Month = l_ThisDateEventParts.get(1)
  73.                  v_ThisDateEvent_Day = l_ThisDateEventParts.get(0)
  74.                  l_ThisTimeEventParts = l_ThisDateTimeEventParts.get(1).toList(":")
  75.                  v_ThisDateEvent_Minute = l_ThisTimeEventParts.get(1)
  76.                  v_ThisDateEvent_Hour = l_ThisTimeEventParts.get(0)
  77.                  // 
  78.                  // convert 12-hour to 24-hour 
  79.                  v_ThisDateEvent_Hour = if(l_ThisDateTimeEventParts.get(2)=="PM", v_ThisDateEvent_Hour.toLong() + 12, v_ThisDateEvent_Hour)
  80.                  v_ThisDateEvent_Hour = if(v_ThisDateEvent_Hour.toLong()==24, "12", v_ThisDateEvent_Hour)
  81.                  // 
  82.                  v_ThisEventDate = v_ThisDateEvent_Year + "-" + v_ThisDateEvent_Month + "-" + v_ThisDateEvent_Day; 
  83.                  v_ThisEventDateSort = v_ThisDateEvent_Year.toString() + v_ThisDateEvent_Month.toString() + v_ThisDateEvent_Day.toString() + v_ThisDateEvent_Hour.toString() + v_ThisDateEvent_Minute.toString() + ifnull(m_PastEvent.get("title"),"?").trim().toLowerCase()
  84.                  v_ThisEventStart = v_ThisDateEvent_Year + "-" + v_ThisDateEvent_Month + "-" + v_ThisDateEvent_Day + " " + v_ThisDateEvent_Hour + ":" + v_ThisDateEvent_Minute + ":00"
  85.                  // 
  86.                  // date and time obtained... do your other stuff here 
  87.              } 
  88.          } 
  89.      } 
  90.  } 
  91.  // 
  92.  // get all future events 
  93.  // NB: status=open are upcoming events; status=closed are events in the past; status is a mandatory field 
  94.  // NB: range is an integer and the number of records to return (default=100; max=200) 
  95.  // NB: index is an integer and is the offset or starting index (not the ID of the record) 
  96.  m_Params = Map()
  97.  m_Params.put("range",50)
  98.  m_Params.put("status","open")
  99.  v_EndpointEvents = v_BaseURL + "/restapi/portal/" + v_PortalID + "/projects/" + v_ProjectID + "/events/"
  100.  r_FutureEvents = invokeurl 
  101.  [ 
  102.      url :v_EndpointEvents 
  103.      type :GET 
  104.      parameters:m_Params 
  105.      connection:"my_projects_connection" 
  106.  ]
  107.  l_FutureEvents = ifnull(r_FutureEvents.get("events"),List())

Additional: Code to get a single event:
The above is great on a test system where you don't have many events, but what if this the system has far more than 50 events, past or upcoming? Here's the code to get a single event record by its record ID. Note that this isn't in the official documentation but at time of print, this works:
copyraw
//
// get event record by ID
v_EndpointEvent = v_BaseURL + "/restapi/portal/" + v_PortalID + "/projects/" + v_ProjectID + "/events/" + v_EventID + "/";
r_ThisEvent = invokeurl
[
	url :v_EndpointEvent
	type :GET
	connection:"my_projects_connection"
];
info r_ThisEvent;
  1.  // 
  2.  // get event record by ID 
  3.  v_EndpointEvent = v_BaseURL + "/restapi/portal/" + v_PortalID + "/projects/" + v_ProjectID + "/events/" + v_EventID + "/"
  4.  r_ThisEvent = invokeurl 
  5.  [ 
  6.      url :v_EndpointEvent 
  7.      type :GET 
  8.      connection:"my_projects_connection" 
  9.  ]
  10.  info r_ThisEvent; 

Source(s):

Category: Zoho Projects :: Article: 407

Accreditation

Badge - Zoho Creator Certified Developer Associate
Badge - Zoho Deluge Certified Developer
Badge - Certified Zoho CRM Developer

Donate & Support

If you like my content, and would like to support this sharing site, feel free to donate using a method below:

Paypal:
Donate to Joel Lipman via PayPal

Bitcoin:
Donate to Joel Lipman with Bitcoin bc1qf6elrdxc968h0k673l2djc9wrpazhqtxw8qqp4

Ethereum:
Donate to Joel Lipman with Ethereum 0xb038962F3809b425D661EF5D22294Cf45E02FebF

Credit where Credit is Due:


Feel free to copy, redistribute and share this information. All that we ask is that you attribute credit and possibly even a link back to this website as it really helps in our search engine rankings.

Disclaimer: Please note that the information provided on this website is intended for informational purposes only and does not represent a warranty. The opinions expressed are those of the author only. We recommend testing any solutions in a development environment before implementing them in production. The articles are based on our good faith efforts and were current at the time of writing, reflecting our practical experience in a commercial setting.

Thank you for visiting and, as always, we hope this website was of some use to you!

Kind Regards,

Joel Lipman
www.joellipman.com