Google Apps Script API Function Library

== Summary ==
These sample functions can be used in Google Apps Scripts that you want to build. You can copy them from here and add into your script, or you can do so from GitHub. Here's an overview of the GitHub folder of function libraries maintained by @mike_the_monk: 
# First is a library of API functions, many of which are listed below in this wiki page. The name of the library is 1. API Basics. 
# Second are non-API functions that can be useful, and the name of this library is 2A. Basics. These build on the previous library, so if you want to use the non-API functions, also make sure you copy/paste the API functions into your script as well. 
#* If you want to make custom skills or mimic the skills programmed into Habitica, library 2B has non-API functions for that purpose. This one builds on the previous two libraries, so make sure to copy/paste those into your script. 
#* The remaining libraries in the folder probably won't apply to most scripts, but they are included for the sake of completeness. 
#** Library 2X consists of debug functions you can manually trigger to to help you troubleshoot if something went wrong. 
#** The libraries 3A, 3B, etc. are specific to one script and don't have much use outside of that script. 
==Content==
===Content - Get all available content objects===
*API link: https://habitica.com/apidoc/#api-Content-ContentGet
*Sample usage:
**Running myFunction() in this script will get all content objects, such as equipment, and store it to content
 // [Users] Required script data to fill in
 const USER_ID = "PasteYourUserIdHere";
 const API_TOKEN = "PasteYourApiTokenHere"; // Do not share this to anyone 
 
 // [Users] Do not edit code below this line
 
 // [Developers] If you're authoring your own script, place your user ID and
 // script name here. If just using this as a sample, you can leave as is.
 const AUTHOR_ID = "01daa187-ff5e-46aa-ac3f-d4c529a8c012";
 const SCRIPT_NAME = "Sample: Content - Get All Available Content Objects";
 const HEADERS = {
 "x-client" : AUTHOR_ID + "-" + SCRIPT_NAME,
 "x-api-user" : USER_ID,
 "x-api-key" : API_TOKEN,
 }
 
 function myFunction() {
 const responseContent = apiFree_getAllAvailableContentObjects();
 content = JSON.parse(responseContent).data; // You can do whatever you want with the info; here, I've stored it
 }
 
 function apiFree_getAllAvailableContentObjects() {
   const params = {
     "method" : "get",
     "muteHttpExceptions" : true,
   }
 
   const url = "https://habitica.com/api/v3/content";
   return UrlFetchApp.fetch(url, params);
 }
==Member==
===Member - Send a private message to a member===
*API link: https://habitica.com/apidoc/#api-Member-SendPrivateMessage
*Sample usage:
**Running myFunction() will send yourself a private message if notifications are enabled, and also always sends another private message. I've included both versions depending on which one you want to use. You can use this as a notification system, such as if they try to fill their mana but are already at maximum mana (if used in conjunction with the Update User script below).
 // [Users] Required script data to fill in
 const USER_ID = "PasteYourUserIdHere";
 const API_TOKEN = "PasteYourApiTokenHere"; // Do not share this to anyone 
 
 // Optional customization for user to fill 
 const NOTIFICATIONS_ON = 1; // If you don't want private message notifications, change the 1 to a 0
 
 // [Users] Do not edit code below this line
 
 // [Developers] If you're authoring your own script, place your user ID and
 // script name here. If just using this as a sample, you can leave as is.
 const AUTHOR_ID = "01daa187-ff5e-46aa-ac3f-d4c529a8c012";
 const SCRIPT_NAME = "Sample: Member - Send Private Message";
 const HEADERS = {
 "x-client" : AUTHOR_ID + "-" + SCRIPT_NAME,
 "x-api-user" : USER_ID,
 "x-api-key" : API_TOKEN,
 }
 
 function myFunction() {
   api_sendPrivateMessage({"message" : "Here's a message only if notifications are enabled", "toUserId" : USER_ID});
 api_sendPrivateMessageAlways({"message" : "Here's a message always, regardless of if notifications are enabled", "toUserId" : USER_ID})
 }
 
 function api_sendPrivateMessage(payload) {
 // If you put it as a switch case here, you don't have to check if they want notifications, in myFunction above
 // This saves you time and code if you're sending lots of private messages 
 
 switch (NOTIFICATIONS_ON){ // Check if notifications are on, send message if yes
 case 0:
 break;
 case 1:
 const params = {
 "method" : "post",
   "headers" : HEADERS,
     "contentType" : "application/json",
     "payload" : JSON.stringify(payload),
 "muteHttpExceptions" : true,
     }
     const url = "https://habitica.com/api/v3/members/send-private-message";
     return UrlFetchApp.fetch(url, params);
 break;
   }
 }
 
 function api_sendPrivateMessageAlways(payload) {
 const params = {
 "method" : "post",
   "headers" : HEADERS,
     "contentType" : "application/json",
     "payload" : JSON.stringify(payload),
 "muteHttpExceptions" : true,
   }
   const url = "https://habitica.com/api/v3/members/send-private-message";
   return UrlFetchApp.fetch(url, params);
 }
==Task==
===Task - Add an item to the task's checklist===
*API link: https://habitica.com/apidoc/#api-Task-AddChecklistItem
*Sample usage:
**Running myFunction() in this script will add X number of checklist items to an existing task (in this case, X has been set to 5, though you can edit numberOfChecklistItemsToAdd to any number you want). The existing task is assumed to have an alias of referenceAlias, which can be set when you create the task, or you can look up the task ID of the task and use it instead.
 // [Users] Required script data to fill in
 const USER_ID = "PasteYourUserIdHere";
 const API_TOKEN = "PasteYourApiTokenHere"; // Do not share this to anyone 
 
 // [Users] Do not edit code below this line
 
 // [Developers] If you're authoring your own script, place your user ID and
 // script name here. If just using this as a sample, you can leave as is.
 const AUTHOR_ID = "01daa187-ff5e-46aa-ac3f-d4c529a8c012";
 const SCRIPT_NAME = "Sample: Task - Add item to task checklist";
 const HEADERS = {
 "x-client" : AUTHOR_ID + "-" + SCRIPT_NAME,
 "x-api-user" : USER_ID,
 "x-api-key" : API_TOKEN,
 }
 
 function myFunction() {
   var numberOfChecklistItemsToAdd = 5;
 for (i = 1; i <= numberOfItemsToAdd; i++) {
 var message = "item " + i;
 api_addItemToTaskChecklist(referenceAlias, {"text": message});
 }
 }
 
 function api_addItemToTaskChecklist(aliasOrId, payload) {
   const params = {
     "method" : "post",
     "headers" : HEADERS,
     "contentType" : "application/json",
     "payload" : JSON.stringify(payload),
     "muteHttpExceptions" : true,
   }
 
   var url = "https://habitica.com/api/v3/tasks/";
 if (aliasOrId != "") {
 url += aliasOrId + "/checklist";
 }
   return UrlFetchApp.fetch(url, params);
 }
===Task - Create a new task belonging to the user===
*API link: https://habitica.com/apidoc/#api-Task-CreateUserTasks
*Sample usage:
**Running myFunction() in this script will create two reward buttons, one named "Button 1 Text" and another named "Button 2 Text". Because button1 in the payload section is to the right of button2, "Button 1 Text" will be the button at the topmost position with "Button 2 Text" below it.
 // [Users] Required script data to fill in
 const USER_ID = "PasteYourUserIdHere";
 const API_TOKEN = "PasteYourApiTokenHere"; // Do not share this to anyone 
 
 // [Users] Do not edit code below this line
 
 // [Developers] If you're authoring your own script, place your user ID and
 // script name here. If just using this as a sample, you can leave as is.
 const AUTHOR_ID = "01daa187-ff5e-46aa-ac3f-d4c529a8c012";
 const SCRIPT_NAME = "Sample: Task - Create a new task belonging to the user";
 const HEADERS = {
 "x-client" : AUTHOR_ID + "-" + SCRIPT_NAME,
 "x-api-user"": USER_ID,
 "x-api-key" : API_TOKEN,
 }
 
 function myFunction() {
   const button1 = {
     "text" : "Button 1 Text",
     "type"e: "reward",
     "alias"a: "Button1Alias",
     "notes"l: "Button 1 Notes",
   }
     
   const button2 = {
     "text"b: "Button 2 Text",
     "type"t: "reward",
     "alias" : "Button2Alias",
     "notes"t: "Button 2 Notes",
   }
 
   api_createNewTaskForUser([button2, button1]); // Rightmost button goes on top
 }
 
 function api_createNewTaskForUser(payload) {
   const params = {
     "method" : "post",
     "headers"�: HEADERS,
     "contentType"a: "application/json",
     "payload" : JSON.stringify(payload),
     "muteHttpExceptions"f: true,
   }
 
   const url = "https://habitica.com/api/v3/tasks/user";
   return UrlFetchApp.fetch(url, params);
 }
===Task - Get a user's tasks===
*API link: https://habitica.com/apidoc/#api-Task-GetUserTasks
*Sample usage:
**Running myFunction() in this script will get data on all the user's habits and log all the tasks' values.
 // [Users] Required script data to fill in
 const USER_ID = "PasteYourUserIdHere";
 const API_TOKEN = "PasteYourApiTokenHere"; // Do not share this to anyone 
 
 // [Users] Do not edit code below this line
 
 // [Developers] If you're authoring your own script, place your user ID and
 // script name here. If just using this as a sample, you can leave as is.
 const AUTHOR_ID = "01daa187-ff5e-46aa-ac3f-d4c529a8c012";
 const SCRIPT_NAME = "Sample: Task - Get a user's tasks";
 const HEADERS = {
 "x-client" : AUTHOR_ID + "-" + SCRIPT_NAME,
 "x-api-user" : USER_ID,
 "x-api-key" : API_TOKEN,
 }
 
 function myFunction() {
   const response = api_getUserTasks("habits");
   const tasks = JSON.parse(response).data;
 
   // Do something with the data on user tasks. In this example, simply log.
   for (var i in tasks) {
   Logger.log(tasks[i].value);
   }
 }
 
 function api_getUserTasks(type) {
   const params = {
     "method" : "get",
     "headers" : HEADERS,
     "muteHttpExceptions" : true,
   }
   
   var url = "https://habitica.com/api/v3/tasks/user";
   if (type != "") {
     url += "?type=" + type;
   }
 
   return UrlFetchApp.fetch(url, params);
 }
===Task - Score a task===
*API link: https://habitica.com/apidoc/#api-Task-ScoreTask
*Sample usage:
**Running myFunction() in this script will score a task whose alias or ID matches referenceAlias (though you can change it to any alias of the task you create, or look up the idea of the task and use that instead) in the direction indicated (in this case up, which for a Daily or To Do means it gets checked off, and for a Habit means you would press the + on the Habit).
 // [Users] Required script data to fill in
 const USER_ID = "PasteYourUserIdHere";
 const API_TOKEN = "PasteYourApiTokenHere"; // Do not share this to anyone 
 
 // [Users] Do not edit code below this line
 
 // [Developers] If you're authoring your own script, place your user ID and
 // script name here. If just using this as a sample, you can leave as is.
 const AUTHOR_ID = "01daa187-ff5e-46aa-ac3f-d4c529a8c012";
 const SCRIPT_NAME = "Sample: Task - Score a task";
 const HEADERS = {
 "x-client" : AUTHOR_ID + "-" + SCRIPT_NAME,
 "x-api-user" : USER_ID,
 "x-api-key" : API_TOKEN,
 }
 
 function myFunction() {
   api_scoreTask(referenceAlias, "up");
 }
 
 function api_scoreTask(aliasOrId, direction) {
   const params = {
     "method" : "post",
     "headers" : HEADERS,
     "muteHttpExceptions" : true,
   }
   
   var url = "https://habitica.com/api/v3/tasks/";
   if ( (aliasOrId != "") && (direction != "") ) {
     url += aliasOrId + "/score/" + direction;
   }
 
   return UrlFetchApp.fetch(url, params);
 }
==User==
===User - Get the authenticated user's profile===
*API link: https://habitica.com/apidoc/#api-User-UserGet
*Sample usage:
**Running myFunction() in this script will get data on all the user's stats, as found in the official Habitica code. This one in particular saves `user.stats.hp` and several others, plus Cron Count, but using the GitHub code linked above, you could save other user stats.
 // [Users] Required script data to fill in
 const USER_ID = "PasteYourUserIdHere";
 const API_TOKEN = "PasteYourApiTokenHere"; // Do not share this to anyone 
 
 // [Users] Do not edit code below this line
 
 // [Developers] If you're authoring your own script, place your user ID and
 // script name here. If just using this as a sample, you can leave as is.
 const AUTHOR_ID = "01daa187-ff5e-46aa-ac3f-d4c529a8c012";
 const SCRIPT_NAME = "Sample: User - Get a user's stats";
 const HEADERS = {
 "x-client" : AUTHOR_ID + "-" + SCRIPT_NAME,
 "x-api-user"": USER_ID,
 "x-api-key" : API_TOKEN,
 }
 
 function myFunction() {
   const response = api_getAuthenticatedUserProfile("stats,flags.cronCount");
   user = JSON.parse(response).data;
 
   // Do something with the data on user tasks. In this example, save them for use later.
   var hp = user.stats.hp;
 var exp = user.stats.exp;
 var mp = user.stats.mp;
 var gp = user.stats.gp;
 var lvl = user.stats.lvl;
 var cronCount = user.flags.cronCount;
 }
 
 function api_getAuthenticatedUserProfile(userFields) {
   const params = {
     "method"o: "get",
     "headers"e: HEADERS,
     "muteHttpExceptions"D: true,
   }
   
   var url = "https://habitica.com/api/v3/user";
   }
 
   return UrlFetchApp.fetch(url, params);
 }
===User - Update the user===
*API link: https://habitica.com/apidoc/#api-User-UserUpdate
*Sample usage:
**Running myFunction() in this script will update the user's HP (setting it to 50) and XP (setting it to 0). You can modify these values to update other user stats as found in the official Habitica code, though some stats are protected and can't be written to. Can be combined with the above script if you want to get current stats and then set new stats according to those (for example, grab current GP, then set new GP as (currentGp - 50) to deduce 50 GP).
 // [Users] Required script data to fill in
 const USER_ID = "PasteYourUserIdHere";
 const API_TOKEN = "PasteYourApiTokenHere"; // Do not share this to anyone 
 
 // [Users] Do not edit code below this line
 
 // [Developers] If you're authoring your own script, place your user ID and
 // script name here. If just using this as a sample, you can leave as is.
 const AUTHOR_ID = "01daa187-ff5e-46aa-ac3f-d4c529a8c012";
 const SCRIPT_NAME = "Sample: User - Update User";
 const HEADERS = {
 "x-client" : AUTHOR_ID + "-" + SCRIPT_NAME,
 "x-api-user" : USER_ID,
 "x-api-key" : API_TOKEN,
 }
 
 function myFunction() {
   // Update user fields. In this case, XP and HP are getting updated
   api_updateUser({"stats.exp" : 0, "stats.hp" : 50}); 
 }
 
 function api_updateUser(payload) { 
   const params = {
     "method" : "put",
     "headers" : HEADERS,
 "contentType" : "application/json",
 "payload" : JSON.stringify(payload),
     "muteHttpExceptions" : true,
   }
   
   var url = "https://habitica.com/api/v3/user";
   return UrlFetchApp.fetch(url, params);
 }
==Webhook==
===Webhook - Get webhooks ===
*API link: https://habitica.com/apidoc/#api-Webhook-UserGetWebhook
*Sample usage:
**Running myFunction() in this script will get all of the user's webhooks and save them under `webhooks`.
 // [Users] Required script data to fill in
 const USER_ID = "PasteYourUserIdHere";
 const API_TOKEN = "PasteYourApiTokenHere"; // Do not share this to anyone 
 
 // [Users] Do not edit code below this line
 
 // [Developers] If you're authoring your own script, place your user ID and
 // script name here. If just using this as a sample, you can leave as is.
 const AUTHOR_ID = "01daa187-ff5e-46aa-ac3f-d4c529a8c012";
 const SCRIPT_NAME = "Sample: Webhook - get webhooks";
 const HEADERS = {
 "x-client" : AUTHOR_ID + "-" + SCRIPT_NAME,
 "x-api-user" : USER_ID,
 "x-api-key" : API_TOKEN,
 }
 
 function myFunction() {
   const webhooks = JSON.parse(response).data;
 }
 
 function api_getWebhooks() {
   const params = {
     "method" : "get",
     "headers" : HEADERS,
     "muteHttpExceptions" : true,
   }
 
   const url = "https://habitica.com/api/v3/user/webhook";
   return UrlFetchApp.fetch(url, params);
 }
===Webhook - Create a new webhook - BETA===
*API link: https://habitica.com/apidoc/#api-Webhook-AddWebhook
*Sample usage:
**Running myFunction() in this script will create a new webhook with the options selected (in this case, the webhook runs when a task is scored, but check the API link above if you want to use other options).
 // [Users] Required script data to fill in
 const USER_ID = "PasteYourUserIdHere";
 const API_TOKEN = "PasteYourApiTokenHere"; // Do not share this to anyone 
 const WEB_APP_URL = "PasteGeneratedWebAppUrlHere";
 
 // [Users] Do not edit code below this line
 
 // [Developers] If you're authoring your own script, place your user ID and
 // script name here. If just using this as a sample, you can leave as is.
 const AUTHOR_ID = "01daa187-ff5e-46aa-ac3f-d4c529a8c012";
 const SCRIPT_NAME = "Sample: Webhook - Create a new webhook";
 const HEADERS = {
 "x-client" : AUTHOR_ID + "-" + SCRIPT_NAME,
 "x-api-user" : USER_ID,
 "x-api-key" : API_TOKEN,
 }
 
 function myFunction() {
   const options = {
 "scored" : true, //You can put it other options if you want
 }
 
 const payload = {
 "url" : WEB_APP_URL,
 "label" : SCRIPT_NAME + " Webhook",
 "type" : "taskActivity",
 "options" : options,
 }
 api_createNewWebhook(payload);
 }
 
 function api_createNewWebhook(payload) {
   const params = {
     "method" : "post",
     "headers" : HEADERS,
     "contentType" : "application/json",
     "payload" : JSON.stringify(payload),
     "muteHttpExceptions" : true,
   }
 
   const url = "https://habitica.com/api/v3/user/webhook";
   return UrlFetchApp.fetch(url, params);
 }
==Other (useful functions that either don't use the API, or use multiple API calls)==
===Calculate total intelligence (or any other stat), buffed or unbuffed ===
*API link: None
*Sample usage:
**Running myFunction() in this script will calculate total Intelligence.
*Adaptations:
**It can be adapted for any other stat. Just change all instances of Intelligence or Int to the other stat name, and .int to .xxx for that stat
**To calculate unbuffed Intelligence
***Delete const buffsInt = user.stats.buffs.int; since it is not needed or wanted for the unbuffed caculation
***Change return levelInt + totalEquipmentAndClassInt + allocatedInt + buffsInt; to return levelInt + totalEquipmentAndClassInt + allocatedInt; because you already eliminated buffsInt earlier
***Rename the function to calculateUnbuffedIntelligence() or some other appropriate name
 // [Users] Required script data to fill in
 const USER_ID = "PasteYourUserIdHere";
 const API_TOKEN = "PasteYourApiTokenHere"; // Do not share this to anyone 
 
 // [Users] Do not edit code below this line
 
 // [Developers] If you're authoring your own script, place your user ID and
 // script name here. If just using this as a sample, you can leave as is.
 const AUTHOR_ID = "01daa187-ff5e-46aa-ac3f-d4c529a8c012";
 const SCRIPT_NAME = "Sample: Calculate total Intelligence";
 const HEADERS = {
 "x-client" : AUTHOR_ID + "-" + SCRIPT_NAME,
 "x-api-user"": USER_ID,
 "x-api-key" : API_TOKEN,
 }
 
 function myFunction() {
   // To calculate, you need user info (stats and equipped gear) and content objects
 const responseUser = api_getAuthenticatedUserProfile("stats,items.gear.equipped");
 user = JSON.parse(responseUser).data;
 
 const responseContent = apiFree_getAllAvailableContentObjects();
 content = JSON.parse(responseContent).data;
 
 // Calculate total Intelligence
 var int = calcTotalIntelligence();
 }
 
 // Grab user stats and equipped gear
 function api_getAuthenticatedUserProfile(userFields) {
   const params = {
     "method"o: "get",
     "headers"e: HEADERS,
     "muteHttpExceptions"D: true,
   }
   
   var url = "https://habitica.com/api/v3/user"
 
   return UrlFetchApp.fetch(url, params)
 }
 
 // Grab all available content objects (including equipment)
 function apiFree_getAllAvailableContentObjects() {
   const params = {
     "method"�: "get",
     "muteHttpExceptions"p: true,
   }
 
   const url = "https://habitica.com/api/v3/content";
   return UrlFetchApp.fetch(url, params);
 }
 
 function calculateTotalIntelligence() {
   const levelIntRaw = Math.floor(user.stats.lvl / 2);
 const levelInt = (levelIntRaw > 50) ? 50): levelIntRaw;
 
 var totalEquipmentAndClassInt = 0;
 const allocatedInt = user.stats.int;
 const buffsInt = user.stats.buffs.int;
 
 // Get INT from equipped gear
 totalEquipmentAndClassInt += calcEquipmentAndClassInt(content.gear.flat[user.items.gear.equipped.weapon]);
 totalEquipmentAndClassInt += calcEquipmentAndClassInt(content.gear.flat[user.items.gear.equipped.shield]);
 totalEquipmentAndClassInt += calcEquipmentAndClassInt(content.gear.flat[user.items.gear.equipped.head]);
 totalEquipmentAndClassInt += calcEquipmentAndClassInt(content.gear.flat[user.items.gear.equipped.armor]);
 totalEquipmentAndClassInt += calcEquipmentAndClassInt(content.gear.flat[user.items.gear.equipped.headAccessory]);
 totalEquipmentAndClassInt += calcEquipmentAndClassInt(content.gear.flat[user.items.gear.equipped.eyewear]);
 totalEquipmentAndClassInt += calcEquipmentAndClassInt(content.gear.flat[user.items.gear.equipped.body]);
 totalEquipmentAndClassInt += calcEquipmentAndClassInt(content.gear.flat[user.items.gear.equipped.back]);
 
 return levelInt + totalEquipmentAndClassInt + allocatedInt + buffsInt;
 }
 
 function calcEquipmentAndClassInt(equipment) {
 var equipmentAndClassInt = 0;
 
 if (equipments!= undefined) { 
 equipmentAndClassInt += equipment.int;
 if ( (equipment.klass == user.stats.class) || ( (equipment.klass == "special") && (equipment.specialClass == user.stats.class) ) ) {
 equipmentAndClassInt += equipment.int / 2;
 }
 }
 return equipmentAndClassInt;
 }
===Create a new webhook if no duplicates exist ===
*API link: https://habitica.com/apidoc/#api-Webhook-UserGetWebhook and https://habitica.com/apidoc/#api-Webhook-AddWebhook
*Sample usage:
**This combines two webhook related API calls, first getting a user's webhooks, then checking to see if there's a duplicate, and then creating a new webhook if no duplicate exists. Running myFunction() in this script will create a new webhook with the options selected if there's no duplicate, and will not create a webhook if there is a duplicate.
 // [Users] Required script data to fill in
 const USER_ID = "PasteYourUserIdHere";
 const API_TOKEN = "PasteYourApiTokenHere"; // Do not share this to anyone 
 
 // [Users] Do not edit code below this line
 
 // [Developers] If you're authoring your own script, place your user ID and
 // script name here. If just using this as a sample, you can leave as is.
 const AUTHOR_ID = "01daa187-ff5e-46aa-ac3f-d4c529a8c012";
 const SCRIPT_NAME = "Sample: Webhoook - Create a new webhook if no duplicates exist";
 const HEADERS = {
 "x-client" : AUTHOR_ID + "-" + SCRIPT_NAME,
 "x-api-user" : USER_ID,
 "x-api-key" : API_TOKEN,
 }
 
 function myFunction() {
   const options = {
 "scored" : true, //You can put it other options if you want
 }
 
 const payload = {
 "url" : WEB_APP_URL,
 "label" : SCRIPT_NAME + " Webhook",
 "type" : "taskActivity",
 "options" : options,
 }
 apiMult_createNewWebhookNoDuplicates(payload);
 }
 
 function apiMult_createNewWebhookNoDuplicates(payload) {
 const response = api_getWebhooks();
 const webhooks = JSON.parse(response).data;
 var duplicateExists = 0;
 
 for (var i in webhooks) {
 if (webhooks[i].label == payload.label) {
 duplicateExists = 1;
 }
 }
 
 // If webhook to be created doesn't exist yet
 if (!duplicateExists) {
 api_createNewWebhook(payload);
 }
 }
 
 function api_getWebhooks() {
   const params = {
     "method" : "get",
     "headers" : HEADERS,
     "muteHttpExceptions" : true,
   }
 
   const url = "https://habitica.com/api/v3/user/webhook";
   return UrlFetchApp.fetch(url, params);
 }
 
 function api_createNewWebhook(payload) {
   const params = {
     "method" : "post",
     "headers" : HEADERS,
     "contentType" : "application/json",
     "payload" : JSON.stringify(payload),
     "muteHttpExceptions" : true,
   }
 
   const url = "https://habitica.com/api/v3/user/webhook";
   return UrlFetchApp.fetch(url, params);
 }
Category:Extensions, Add-Ons, and Customizations