Would any one have a sample script or method how to setup Twilio Client to make and receive calls directly in a browser with Google apps script as a webapp or the like.
Here is how to initiate a Twilio call from GAS, but I can't seem to figure out how to do Twilio Client.
function makeCall() {
var to = "+1xxxxxxxxxx";
var from = "+1xxxxxxxxxx";
var callsUrl = "https://api.twilio.com/2010-04-01/Accounts/ACxxxxxxxxxxxx/Calls.json";
var payload = {
"To": to,
"From" : from,
"Twiml" : '<Response><Say>Hello this is a Twilio call</Say></Response>',
};
var options = {
"method" : "post",
"payload" : payload
};
options.headers = {
"Authorization" : "Basic " + Utilities.base64Encode("ACxxxxxxxxxxxxxxxxxxx:xxxxxxxxxxxxxx")
};
var res = UrlFetchApp.fetch(callsUrl, options);
Logger.log(res);
}
Related
I'm going mad trying to send my first API call to Coinbase Pro using Google Apps Script. In node.js is pretty easy (https://docs.pro.coinbase.com/#signing-a-message) but doing the same with Google scripts is just returning again and again "Invalid Signature".
This is the code I'm using:
function GetMyAccounts () {
var globalvars_CB = {
'apikey' : 'f7d20a*******18c',
'secret' : '******pIIitRbWCv9N/mMWaR*****mGQMuI+m/vSbU1zuh5U6WFiFw==',
'passphrase' : 'ceacdsewfcsa',
'uri' : 'https://api.pro.coinbase.com'
}
var requestPath = '/accounts';
var timestamp = Math.floor(Date.now() / 1000);
var options = {
'method' : 'GET',
'muteHttpExceptions' : true,
'headers' : {
'Content-Type': 'application/json',
'CB-ACCESS-KEY' : globalvars_CB.apikey,
'CB-ACCESS-SIGN' : SignAPICall(globalvars_CB.secret, timestamp, 'GET', requestPath, ''),
'CB-ACCESS-TIMESTAMP' : timestamp,
'CB-ACCESS-PASSPHRASE' : globalvars_CB.passphrase,
}
}
var responseJson = UrlFetchApp.fetch(globalvars_CB.uri+requestPath, options);
Logger.log(responseJson);
}
function SignAPICall(secret, timestamp, method, requestPath, body) {
var what = (timestamp + method + requestPath + body);
var decodedsecret = Utilities.base64Decode(secret).toString();
var hmac = Utilities.computeHmacSha256Signature(what, decodedsecret);
hmac = Utilities.base64Encode(hmac);
return (hmac);
}
I really need help :-) - Thanks!
In your script, it supposes that your request headers except for the value of CB-ACCESS-SIGN and endpoint are correct. Please be careful this.
Modification point:
In the case of Utilities.base64Decode(secret).toString(), the array is converted to the string. I think that this might be the reason of your issue.
When above point is reflected, it becomes as follows.
Modified script:
In this case, the function SignAPICall is modified.
function SignAPICall(secret, timestamp, method, requestPath, body) {
var what = (timestamp + method + requestPath + body);
var decodedsecret = Utilities.base64Decode(secret); // Modified
var res = Utilities.computeHmacSha256Signature(Utilities.newBlob(what).getBytes(), decodedsecret); // Modified
hmac = Utilities.base64Encode(res);
return hmac;
}
In this case, value and key of computeHmacSha256Signature(value, key) are the byte array.
Note:
When I checked above modified script by comparing the sample scripts of the official document, I could confirm that the same result can be obtained.
Unfortunately, I cannot test the request to the API using above modified script while I can confirm that the same signature from the sample script at the official document is retrieved from the above modified script. So please test the request in you environment. When you requested to the API using above modified script, when an error occurs, please check the request headers, endpoint and secret, again.
References:
Signing a Message
base64Decode(encoded)
computeHmacSha256Signature(value, key)
I finally found the solution to it. It was a problem with the type of data I submitted to "Utilities.computeHmacSha256Signature". In the code you can find the function working well.
function SignAndCallAPI(method, requestPath, body) {
var timestamp = Math.floor(Date.now() / 1000).toString();
var what = Utilities.base64Decode(Utilities.base64Encode(timestamp + method + requestPath + body));
var decodedsecret = Utilities.base64Decode(globalvars_CB.secret);
var hmac = Utilities.base64Encode(Utilities.computeHmacSha256Signature(what, decodedsecret));
var options = {
'method' : method,
'muteHttpExceptions' : true,
'headers' : {
'Content-Type': 'application/json',
'CB-ACCESS-KEY' : globalvars_CB.apikey,
'CB-ACCESS-SIGN' : hmac,
'CB-ACCESS-TIMESTAMP' : timestamp,
'CB-ACCESS-PASSPHRASE' : globalvars_CB.passphrase,
}
}
var responseJson = UrlFetchApp.fetch(globalvars_CB.uri+requestPath, options);
Logger.log(responseJson);
return(responseJson);
}
I am using the following code to make requests to the Spotify API via Google Apps Script:
function search() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sheet = ss.getActiveSheet();
var artist = sheet.getRange(1,1).getValue();
artist = encodeURIComponent(artist.trim());
var result = searchSpotify(artist);
Logger.log(result);
}
function searchSpotify(artist) {
//searches spotify and returns artist ID
var response = UrlFetchApp.fetch("https://api.spotify.com/v1/search?q=" + artist + "&type=artist&limit=1",
{ method: "GET",
headers:{
"contentType": "application/json",
'Authorization': "Bearer BQBnpSUdaEweirImw23yh2DH8OGhTwh5a_VnY_fgb2BPML0KvFvYd04CaEdUhQN9N4ZUXMIVfJ1MjFe1_j0Gl0UoHDhcoC_dklluZyOkq8Bo6i2_wfxSbGzP3k5EUjUKuULAnmTwCdkdZQnl-SNU0Co"
},
});
json = response.getContentText();
var data = JSON.parse(json);
var uri = data.artists.items[0].uri.slice(15);
var getArtists = getRelatedArtists(uri);
Logger.log(getArtists);
return getArtists;
}
function getRelatedArtists(uri) {
//searches related artists with the returned ID
var response = UrlFetchApp.fetch("https://api.spotify.com/v1/artists/" + uri + "/related-artists",
{ method: "GET",
headers:{
"contentType": "application/json",
'Authorization': "Bearer BQBnpSUdaEweirImw23yh2DH8OGhTwh5a_VnY_fgb2BPML0KvFvYd04CaEdUhQN9N4ZUXMIVfJ1MjFe1_j0Gl0UoHDhcoC_dklluZyOkq8Bo6i2_wfxSbGzP3k5EUjUKuULAnmTwCdkdZQnl-SNU0Co"
},
});
json = response.getContentText();
var data = JSON.parse(json);
var listArtists = [];
for(var i = 0, len = data.artists.length; i < len; i++){
listArtists.push(data.artists[i].name);
}
return listArtists;
}
This works fine using the temporary Authorisation token from the Spotify website but this token refreshes every hour and so is obviously useless.
I am trying to use my own Authorisation token and ID which I have setup on Spotify however I'm struggling to make this work. As I understand it I may need to add an extra step at the beginning to start the authorisation process but I've tried all methods suggested but keep receiving server errors.
From the document, it seems that "Client Credentials Flow" uses the basic authorization.
In order to use this, at first, you are required to retrieve "client_id" and "client_secret".
Sample script:
var clientId = "### client id ###"; // Please set here.
var clientSecret = "### client secret ###"; // Please set here.
var url = "https://accounts.spotify.com/api/token";
var params = {
method: "post",
headers: {"Authorization" : "Basic " + Utilities.base64Encode(clientId + ":" + clientSecret)},
payload: {grant_type: "client_credentials"},
};
var res = UrlFetchApp.fetch(url, params);
Logger.log(res.getContentText())
From curl sample, grant_type is required to send as form.
Result:
The document says that the response is as follows.
{
"access_token": "NgCXRKc...MzYjw",
"token_type": "bearer",
"expires_in": 3600,
}
Note:
This is a simple sample script. So please modify this for your situation.
I prepared this sample script by the sample curl in the document.
Reference:
Client Credentials Flow
Edit:
As your next issue, you want to retrieve the access token from the returned value. If my understanding is correct, how about this modification? Please modify my script as follows.
From:
Logger.log(res.getContentText())
To:
var obj = JSON.parse(res.getContentText());
Logger.log(obj.access_token)
When the value is returned from API, it returns as a string. So it is required to parse it as an object using JSON.parse().
I am trying to follow documentation but never get the 0Auth2 to connect.
Btw I'm running the script manually from the google sheets scripting page, where should I get prompting for allowing access?
(I don't understand all this 0Auth2 scheme and I have already gave authorization to run the script and got client id and secret)...
See below my log and script routines (the first get to photo is still minimalistic as I didn't yet get through the 0Auth2 step ;-) .
Thanks in advance for any hint. I thought it would be trivial as it is my own sheet and google photo account...
Log:
[19-01-06 17:50:05:809 CET] starting
[19-01-06 17:50:05:810 CET] getPhotoService
[19-01-06 17:50:05:849 CET] false
[19-01-06 17:50:05:850 CET] redirectURI=https://script.google.com/macros/d/[REMOVED]/usercallback
[19-01-06 17:50:05:864 CET] Open the following URL and re-run the script: https://accounts.google.com/o/oauth2/auth?client_id=[removed].apps.googleusercontent.com&response_type=code&redirect_uri=https%3A%2F%2Fscript.google.com%2Fmacros%2Fd%2F[removed]%2Fusercallback&state=[removed]&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fphotoslibrary.readonly&login_hint=[removed]&access_type=offline&approval_prompt=force
Script:
function getPhotoService() {
// Create a new service with the given name. The name will be used when
// persisting the authorized token, so ensure it is unique within the
// scope of the property store.
Logger.log('getPhotoService');
return OAuth2.createService('gPHOTOfj')
// enable caching on the service, so as to not exhaust script's PropertiesService quotas
.setPropertyStore(PropertiesService.getUserProperties())
.setCache(CacheService.getUserCache())
// Set the endpoint URLs, which are the same for all Google services.
.setAuthorizationBaseUrl('https://accounts.google.com/o/oauth2/auth')
.setTokenUrl('https://accounts.google.com/o/oauth2/token')
// Set the client ID and secret, from the Google Developers Console.
.setClientId(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
// Set the name of the callback function in the script referenced
// above that should be invoked to complete the OAuth flow.
.setCallbackFunction('authCallback')
//.setCallbackFunction('https://script.google.com/macros/d/'+SCRIPT_ID+'/authCallback')
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getUserProperties())
// Set the scopes to request (space-separated for Google services).
.setScope('https://www.googleapis.com/auth/photoslibrary.readonly')
// Below are Google-specific OAuth2 parameters.
// Sets the login hint, which will prevent the account chooser screen
// from being shown to users logged in with multiple accounts.
.setParam('login_hint', Session.getActiveUser().getEmail())
// Requests offline access.
.setParam('access_type', 'offline')
// Forces the approval prompt every time. This is useful for testing,
// but not desirable in a production application.
.setParam('approval_prompt', 'force');
}
function authCallback(request) {
Logger.log('Called back!');
var photoService = getPhotoService();
var isAuthorized = photoService.handleCallback(request);
if (isAuthorized) {
Logger.log('Authorisation Success!');
} else {
Logger.log('Authorisation Denied...!');
}
}
// Modified from http://ctrlq.org/code/20068-blogger-api-with-google-apps-script
function photoAPI() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var albums_sh = ss.getSheetByName("albums") || ss.insertSheet("albums", ss.getSheets().length);
albums_sh.clear(); var nrow = new Array(); var narray = new Array();
Logger.log("starting");
var service = getPhotoService();
Logger.log(service.hasAccess());
Logger.log('redirectURI='+service.getRedirectUri());
if (service.hasAccess()) {
var api = "https://photoslibrary.googleapis.com/v1/albums";
var headers = {
"Authorization": "Bearer " + service.getAccessToken()
};
var options = {
"headers": headers,
"method" : "GET",
"muteHttpExceptions": true
};
var response = UrlFetchApp.fetch(api, options);
var json = JSON.parse(response.getContentText());
for (var i in json.items) {
nrow = []; nrow.push(json.items[i].id); nrow.push(json.items[i].name); nrow.push(json.items[i].url); narray.push(nrow);
}
albums_sh.getRange(1,1,narray.length,narray[0].length).setValues(narray);
} else {
var authorizationUrl = service.getAuthorizationUrl();
Logger.log("Open the following URL and re-run the script: " + authorizationUrl);
}
}
So it works, if others want to use it. But it is quite slow (I have 500 albums...):
function photoAPI() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var albums_sh = ss.getSheetByName("albums") || ss.insertSheet("albums", ss.getSheets().length);
albums_sh.clear();
var narray = [];
var api = "https://photoslibrary.googleapis.com/v1/albums";
var headers = { "Authorization": "Bearer " + ScriptApp.getOAuthToken() };
var options = { "headers": headers, "method" : "GET", "muteHttpExceptions": true };
var param= "", nexttoken;
do {
if (nexttoken)
param = "?pageToken=" + nexttoken;
var response = UrlFetchApp.fetch(api + param, options);
var json = JSON.parse(response.getContentText());
json.albums.forEach(function (album) {
var data = [
album.title,
album.mediaItemsCount,
album.productUrl
];
narray.push(data);
});
nexttoken = json.nextPageToken;
} while (nexttoken);
albums_sh.getRange(1, 1, narray.length, narray[0].length).setValues(narray);
}
I am trying to make a Pastebin.com paste using Google Apps Script from the spreadsheet script editor. Can anyone tell me what I'm doing wrong?
function postPastebinPost() {
var options, url, apiKey, payload, response;
apiKey = <api key goes here>;
payload = 'Hello World';
options = {
'method' : 'post',
'payload' : payload
};
url = 'https://pastebin.com/api/api_post.php'
+ '?api_dev_key=' + apiKey
+ '&api_option=paste'
+ '&api_paste_code=' + encodeURIComponent(payload);
response = UrlFetchApp.fetch(url, options);
Logger.log(response);
}
I run this and my log reads Bad API request, invalid api_option. I've searched for solutions but I have not found any.
Documentation:
• Pastebin.com API
• Google Apps Script's UrlFetchApp Class
The parameters should be passed in the payload of the POST request.
function postPastebinPost() {
var apiKey = 'YOUR KEY GOES HERE';
var text = 'Hello World';
var payload = {
api_dev_key: apiKey,
api_option: 'paste',
api_paste_code: text
};
var options = {
method : 'POST',
payload: payload
};
var url = 'https://pastebin.com/api/api_post.php';
var response = UrlFetchApp.fetch(url, options);
Logger.log(response.getContentText());
}
The following is in case the user wants to create a new paste as part of their own Pastebin account (and not «Paste as a guest»). It's just an adaptation of Amit Agarwal's answer.
function postPastebinPost() {
var title = 'abc';
var contents = 'Hello World \n next line of content \n more text';
var payload = {
api_dev_key: 'aa6f3ab...', // https://pastebin.com/api#1
api_option: 'paste',
api_paste_name: title,
api_paste_code: contents,
api_paste_private: '0', // public paste
api_user_name: 'diccionario...', // name of your Pastebin account
api_user_password: 'dk398d...', // password to your Pastebin account
api_user_key: '39dk3...', // https://pastebin.com/api/api_user_key.html
};
var options = {
method : 'POST',
payload: payload
};
var url = 'https://pastebin.com/api/api_post.php';
var response = UrlFetchApp.fetch(url, options);
Logger.log(response.getContentText());
}
The whole documentation is at https://pastebin.com/api.
I get this error below when I GET my google apps script.
ERROR: The script completed but did not return anything.
Since I will be posting to my app (which redirects to my app when the post is complete), I should be automatically redirected back to my app?
function doGet(e){
var options = {
"method" : 'POST',
"payload" : "user_id="+e.parameter.user_id+"&gmail="+getEmail()
};
var url = 'http://somedomain.com/users/give_gmail_permission/';
var response = UrlFetchApp.fetch(url, options);
return response;
}
What am I doing wrong? How do I follow HTTPResponse in Google Apps Script?
change the line:
return response
for
return HtmlService.createHtmlOutput("<b>"+response.getResponseCode()+"</b><br>"+response.getContentText()).
setSandboxMode(HtmlService.SandboxMode.NATIVE);
the modified script:
function doGet(e){
var options = {
"method" : 'POST',
"payload" : "user_id="+e.parameter.user_id+"&gmail="+getEmail()
};
var url = 'http://somedomain.com/users/give_gmail_permission/';
var response = UrlFetchApp.fetch(url, options);
Logger.log("response code: "+response.getResponseCode());
Logger.log("response: "+response.getContentText());
return HtmlService.createHtmlOutput("<b>"+response.getResponseCode()+"</b><br>"+response.getContentText()).
setSandboxMode(HtmlService.SandboxMode.NATIVE);
}