Sheets & Appscripts Hubspot POST Request with Authentication Token Problem - google-apps-script

I've created a GAS app to provide better pipeline reporting from our Hubspot instance. So far the app works and I have successfully created a Sales Pipeline that shows up in Google sheets. I am trying to add a capability that requires a POST method to query Hubspot's CRM V3. I got it to work in Postman but cannot replicate it in GAS.
The error I get is "Authentication credentials not found." The headers print to the log so I assume they are being generated properly. My guess is that my access Token and payload are not being passed properly to the API during the request. Any help on the matter would be much appreciated.
function getConversions() {
// Prepare authentication to Hubspot
var service = getService();
var headers = {headers: {'Authorization': 'Bearer ' + service.getAccessToken()}};
Logger.log(headers);
var raw = JSON.stringify({"filterGroups":[{"filters":[{"propertyName":"hs_analytics_last_visit_timestamp","operator":"GT","value":"1561514165666"}]}],"limit":100,"after":0});
var options = {
'method' : 'post',
headers: headers,
'contentType': 'application/json',
// Convert the JavaScript object to a JSON string.
body : raw,
redirect: 'follow',
"muteHttpExceptions": true
};
var response = UrlFetchApp.fetch('https://api.hubapi.com/crm/v3/objects/contacts/search?', options);
var result = JSON.parse(response.getContentText());
Logger.log(result);
};

How about this modification?
Modification points:
When I checked the official document of Search of HubSpot API, I found the curl sample. When this sample is converted to Google Apps Script, I noticed several modification points in your script.
UrlFetchApp.fetch has no properties of body and redirect.
About followRedirects, the official document says as follows.
If false the fetch doesn't automatically follow HTTP redirects; it returns the original HTTP response. The default is true.
In your URL, https://api.hubapi.com/crm/v3/objects/contacts/search? is used. If you don't use the API key, how about modifying to https://api.hubapi.com/crm/v3/objects/contacts/search?
When above modification is reflected to your script, it becomes as follows.
Modified script:
Please modify as follows.
From:
var options = {
'method' : 'post',
headers: headers,
'contentType': 'application/json',
// Convert the JavaScript object to a JSON string.
body : raw,
redirect: 'follow',
"muteHttpExceptions": true
};
To:
var options = {
method : 'post',
headers: headers,
contentType: 'application/json',
payload : raw,
muteHttpExceptions: true
};
Note:
Above modification is required for your script. But I'm worry about the error of Authentication credentials not found.. In this modification, it supposes that your access token of service.getAccessToken() can be used for this request. When I saw the official document, the API key can be also used. If the access token cannot be used, how about using the API key? It's like below.
https://api.hubapi.com/crm/v3/objects/contacts/search?hapikey=YOUR_HUBSPOT_API_KEY
References:
Search of HubSpot API
fetch(url, params)

function getConversions() {
// Prepare authentication to Hubspot
var service = getService();
var headers = {headers: {'Authorization': 'Bearer ' + service.getAccessToken()}};
var url = 'https://api.hubapi.com/crm/v3/objects/contacts/search'
//Logger.log(headers);
var raw = {"filterGroups":[{"filters":[{"propertyName":"hs_analytics_last_visit_timestamp","operator":"GT","value":"1561514165666"}]}],"limit":100,"after":0};
var options = {
method : 'post',
contentType: "application/json",
// Convert the JavaScript object to a JSON string.
payload : JSON.stringify(raw),
muteHttpExceptions: true
};
var response = UrlFetchApp.fetch('https://api.hubapi.com/crm/v3/objects/contacts/search?hapikey=myapikey',options);
var result = JSON.parse(response.getContentText());
Logger.log(response)
Logger.log(result);
};

Related

OAuth 2.0 is not enabled for method Error with jira cloud with App-script

I have implemented oauth2 (3LO) using App-script for integrating Google Sheet and Jira. I have set var SCOPE = read:jira-user read:jira-work write:jira-work
When I use any get request, system works fine. But when I try to make put or post request, system throws error. See this image below:
[][enter code here1]
See here my put request for edit an issue
I am not sure what is the issue here. I have checked that I have enabled oauth2 and as an administrator, I have all power. I have also proper scope. And this configuration works for any get request but it does not work with POST and PUT requests.
Could you please let me know if you have an idea or clue how I can make it work or is there anything I can check to make sure my confirmation is right for POST or PUT requests?
function updateIssue() {
var service = getService();
var issueIdOrKey = 'CP-16'
Logger.log(service.hasAccess());
if (service.hasAccess()) {
var data = `{
"summary":"New summary version 1"
}`;
var route = `/rest/api/3/issue/${issueIdOrKey}`;
var cloudid = getCloudId(service);
var url = 'https://api.atlassian.com/ex/jira/' + cloudid + route;
Logger.log(url);
var response = UrlFetchApp.fetch(url, {
'Method': 'PUT',
headers: {
//'Method': 'PUT',
'Accept': 'application/json',
'Authorization': 'Bearer ' + service.getAccessToken(),
// Convert the JavaScript object to a JSON string.
'ContentType': 'application/json' //, 'payload': JSON.stringify(data)
},
'payload': JSON.stringify(data)
});
var result = JSON.parse(response.getContentText());
Logger.log(JSON.stringify(result, null, 2));
}
}
Thank you
Modification points:
In your script, at var data = {"summary":"New summary version 1"};, data` has already been converted to the string.
When 'ContentType' is used, I thought that it was 'Content-Type'. But, in your script, I thought that 'contentType': 'application/json' can be used outside of the request header.
When these points are reflected in your script, it becomes as follows.
Modified script:
function updateIssue() {
var service = getService();
var issueIdOrKey = 'CP-16'
Logger.log(service.hasAccess());
if (service.hasAccess()) {
var data = { "summary": "New summary version 1" }; // Modified
var route = `/rest/api/3/issue/${issueIdOrKey}`;
var cloudid = getCloudId(service);
var url = 'https://api.atlassian.com/ex/jira/' + cloudid + route;
Logger.log(url);
var response = UrlFetchApp.fetch(url, {
'Method': 'PUT',
'headers': { // Modified
'Accept': 'application/json',
'Authorization': 'Bearer ' + service.getAccessToken(),
},
'contentType': 'application/json', // Added
'payload': JSON.stringify(data)
});
var result = JSON.parse(response.getContentText());
Logger.log(JSON.stringify(result, null, 2));
}
}
Note:
In this modification, it supposes that your access token and your endpoint, and your request body are valid values. Please be careful about this. If an error occurs, please show the error message and please provide the official document of the API you want to use. By this, I would like to confirm it.
Reference:
fetch(url, params)

Fetch JSON object from GAS WebApp from another development GAS WebApp?

I have two different GAS projects Script1 and Script2.
Script1:
It is a development project with doPost() function. It uses the e.parameter or e.postData.contents to do something.
Script2:
It is a test script. It has also doPost() function. I want to transfer the doPost() e.parameter to Script1 by a post request. But the URLFetchApp success when I use the Current web app URL and ends in /exec. But I want to use the latest code and ends in /dev. Because of the Script1 is a development project and I can't update its version for a small change.
I tried this code. It not working
function myFunction() {
//var URL = "https://script.google.com/macros/s/xxxxxxxxxxxxxxxxxxxxxxxxxxx/exec";
var URL = "https://script.google.com/macros/s/xxxxxxxxxxxxxxxxxxxxxxxxxxxx/dev";
var data = {
'message' : "This is working"
}
var options = {
'method' : 'post',
'contentType': 'application/json',
'payload' : JSON.stringify(data)
};
var response = UrlFetchApp.fetch(URL, options);
}
I believe your goal as follows.
You want to access to Web Apps with the dev mode using Google Apps Script.
For this, How about this answer?
Modification points:
In order to access to the Web Apps with the dev mode, please use the access token. And in this sample, the scope of https://www.googleapis.com/auth/drive.readonly is used for the access token.
Modified script:
When your script is modified, please modify as follows.
function myFunction() {
//var URL = "https://script.google.com/macros/s/xxxxxxxxxxxxxxxxxxxxxxxxxxx/exec";
var URL = "https://script.google.com/macros/s/xxxxxxxxxxxxxxxxxxxxxxxxxxxx/dev";
var data = {
'message' : "This is working"
}
var options = {
'method' : 'post',
'contentType': 'application/json',
'payload' : JSON.stringify(data),
'headers': {'authorization': 'Bearer ' + ScriptApp.getOAuthToken()} // Added
};
var response = UrlFetchApp.fetch(URL, options);
}
// DriveApp.getFiles() // Added
Note:
The comment line of // DriveApp.getFiles() is used for automatically detecting the scope of https://www.googleapis.com/auth/drive.readonly by the script editor.
When the access token is used, even when Who has access to the app: is Only myself, the script works.
References:
Web Apps
Taking advantage of Web Apps with Google Apps Script

Stackdriver Logging API returns response code 200, but response is empty

I'm trying to fetch stackdriver logs via Stackdriver Logging API v2. I do this by making a POST request from google apps script project, in particular using UrlFetchApp. The thing is, it runs successfully, but the response shown in log is empty. However, when I made the same request using apirequest.io, curl and Google API explorer, I got the necessary response.
I searched extensively, but to no avail. Tried experimenting with header, url, but nothing.
function exportLogs () {
var options = {
"method" : "post",
"headers": {Authorization: 'Bearer ' + ScriptApp.getOAuthToken()},
"resourceNames": [
"projects/MyProject"
],
"pageSize": 1,
}
var response = UrlFetchApp.fetch('https://logging.googleapis.com/v2/entries:list?key=MyApiKey', options)
Logger.log(response)
}
What I want to get is some logs, but I'm only getting {}
Issue:
Unacceptable keys are used in options object.
Solution:
payload is the only acceptable parameter for including request body.
Code:
function exportLogs() {
var options = {
method: "post",
headers: { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() }, //Include https://www.googleapis.com/auth/cloud-platform in scopes
payload: JSON.stringify({
resourceNames: ['projects/[PROJECT_ID]'],
pageSize: 1,
}),
};
var response = UrlFetchApp.fetch(
'https://logging.googleapis.com/v2/entries:list?key=MyApiKey',
options
);
Logger.log(response);
}
To Read:
Urlfetch#params
Logging api#entriesList
Setting scopes
For some strange reason, adding an orderBy sort property in the request body object is the only way I could get results to be retrieved.
Also, a filter should be added to get only Apps Script logs.
load.filter = 'resource.type="app_script_function"';//Only from Apps Script
See example code at GitHub:
Apps Script Download Stackdriver Logs
Code:
function exportStackdriverLogs() {
var id,load,options,param,response;
id = 'Enter your Cloud Project ID here';//See your console at:
//https://console.cloud.google.com/iam-admin/settings
param = "projects/" + id;
load = {};
load.resourceNames = [param];
load.orderBy = "timestamp desc";
load.filter = 'resource.type="app_script_function"';//Only get logs that
//came from Apps Script
load.pageSize = 1;//You will probably want more than 1 but this is for an example
options = {};
options.method = "post";
options.headers = { Authorization: 'Bearer ' + ScriptApp.getOAuthToken() };
options.payload = JSON.stringify(load);
options.muteHttpExceptions = true;
options.contentType = "application/json";
response = UrlFetchApp.fetch('https://logging.googleapis.com/v2/entries:list',options);
//Logger.log('response: ' + response.getResponseCode())
//Logger.log('content: ' + response.getContentText())
}

How do you access the Google Apps Marketplace UserLicense from Apps Script (for a Sheets add-on)?

I have a Sheets add-on for which I need to know the users license information from GAM (appsmarket/v2/userLicense). Since the user is already logged into Sheets, I wasn't expecting to need to use OAuth, but I'm getting a 403 ("message":"Not authorized to access the application ID"). Is there a way to access the license from Apps Script without using OAuth? Here is my code so far:
function testGetLicense(query) {
var options = {
'method' : 'get',
'contentType': 'application/json',
'muteHttpExceptions' : true
};
var url = 'https://www.googleapis.com/appsmarket/v2/userLicense/1234/xxx#gmail.com'
res = UrlFetchApp.fetch(url, options);
Logger.log(res.getContentText())
}
If I need to use OAuth, should I be using this library?
https://github.com/googlesamples/apps-script-oauth2
Try passing the OAuth Token in the headers.
function testGetLicense(query) {
var options = {
'method' : 'get',
'contentType': 'application/json',
'headers': {
"Authorization": "Bearer " + ScriptApp.getOAuthToken()
},
'muteHttpExceptions' : true
};
var url = 'https://www.googleapis.com/appsmarket/v2/userLicense/1234/xxx#gmail.com'
res = UrlFetchApp.fetch(url, options);
Logger.log(res.getContentText())
}

Google Apps Script: UrlFetchApp Post File

I'm trying to POST a file to a REST API via Google Apps Script. The idea is that I have a process that is creating copies of a Google Doc, and I want to be able to post those newly created Docs to a third party system.
I found in UrlFetchApp that I can send files. However, I'm having issues sending the correct header values.
My request looks like so:
var file = DriveApp.getFileById(fileId);
var body = {
"file": file.getAs(MimeType.PDF)
};
var headers = {
'Content-Disposition': 'attachment; filename="'+ file.getName() +'"',
'Content-Length': file.getSize()
};
My options when I call UrlFetchApp.fetch(url, options) looks like :
({
method:"POST",
headers:{
'Content-Disposition':"attachment; filename=\"My Merge Development_row_1.pdf\"",
'Content-Length':90665,
Authorization:"Bearer TOKEN"
},
contentType:"application/x-www-form-urlencoded",
muteHttpExceptions:true,
payload:{file:Blob}
})
The API that I'm sending the files to requires the 'Content-Length' header. But, when I try to set a value for 'Content-Length' header I get an Apps Script error, "Attribute provided with invalid value: Header:Content-Length". If I don't set the Content-Length header then the API responds that the Content-Length and file size don't match.
Any ideas on how I set the Content-Length header so I can POST the file?
There is an existing ticket highlighting that the documentation is not clear on this very issue
The solution is:
Move content length value from "content-Length" name/value pair in
headers to the advanced argument "contentLength"
So in your example your options should look like
({
method:"POST",
headers:{
'Content-Disposition':"attachment; filename=\"My Merge Development_row_1.pdf\"",
Authorization:"Bearer TOKEN"
},
contentLength: 90665,
contentType:"application/x-www-form-urlencoded",
muteHttpExceptions:true,
payload:{file:Blob}
})
EDIT: Added a full example function to get contentLength and blob shown below:
function testFilePost() {
var file = DriveApp.getFileById(doc_id).getAs(MimeType.PDF);
var headers = {
'Content-Disposition': 'attachment; filename="'+ file.getName() +'"',
};
var options =
{
"method" : "post",
"payload": file.getBytes(),
"headers": headers,
"contentLength": file.getBytes().length,
};
var result = JSON.parse(UrlFetchApp.fetch('http://httpbin.org/post', options).getContentText());
Logger.log(result);
}