Zoho Books API - Google Sheets - api

I am recording my sales details in Google Sheets and am using Zoho Books to maintain my books of accounts. I want to use Zoho Books API to sync data between google sheets and Zoho Books. I have done the following till now:
Created a Self-Client in Zoho API Console to generate a Client ID and Client Secret
Generated an authorization code for all Scopes under Invoices in the Zoho API Console
Generated an access token and refresh token - using Postman
Wrote the following code in Google Apps Script to create an invoice with dummy data
function ZohoInvoice() {
var invoice = {
customer_id: '2298656000000277003',
invoice_number: 'MU001',
date: '2021-09-02',
line_items: [
{
item_id: '2298656000002380000',
name: 'Item1',
description: 'This is the description',
rate: '1500.00',
quantity: '2',
},
],
notes: 'These are the notes of this Invocie'
};
var zohoOauthToken = '1000.827612479824c7c66132118bb242e15942aa6a.4e63c9fd60a343658904a54191c4c32';
var zohoOrganization = '19012342064';
var zohoUrl = [
'https://books.zoho.com/api/v3/invoices?',
'organization_id=',
zohoOrganization,
'&authtoken=',
zohoOauthToken,
'&JSONString=',
encodeURIComponent(JSON.stringify(invoice)),
].join('');
try {
var response = UrlFetchApp.fetch(zohoUrl, {
method: 'POST',
muteHttpExceptions: true,
});
var result = JSON.parse(response.getContentText());
Logger.log(result.message);
} catch (error) {
Logger.log(error.toString());
}
}
The above code throws an error Invalid value passed for authtoken.
Unsure where am I going wrong?

Modification points:
When I saw the official document of "Create an invoice" for Books API, it seems that the sample curl command is as follows.
$ curl https://books.zoho.com/api/v3/invoices?organization_id=10234695
-X POST
-H "Authorization: Zoho-oauthtoken 1000.41d9f2cfbd1b7a8f9e314b7aff7bc2d1.8fcc9810810a216793f385b9dd6e125f"
-H "Content-Type: application/x-www-form-urlencoded;charset=UTF-8"
-F 'JSONString="{,,,}"'
In this case, the token is required to be included in the request header.
But, I thought that in this curl command, the value of JSONString might not be correctly parsed at the server side, because of the content type is application/x-www-form-urlencoded. So I'm not sure whether this sample curl command of this official document is correct. I thought that in this case, -H "Content-Type: application/x-www-form-urlencoded;charset=UTF-8" might not be required to be used. I'm worry about this. So, please test the following modified script.
When above points are reflected to your script, it becomes as follows. The following modified script is from above sample curl command.
Modified script:
Please set zohoOauthToken of your token.
var invoice = {
customer_id: '2298656000000277003',
invoice_number: 'MU001',
date: '2021-09-02',
line_items: [
{
item_id: '2298656000002380000',
name: 'Item1',
description: 'This is the description',
rate: '1500.00',
quantity: '2',
},
],
notes: 'These are the notes of this Invocie'
};
var zohoOauthToken = '###';
var zohoOrganization = '19012342064';
var baseUrl = "https://books.zoho.com/api/v3/invoices";
var url = baseUrl + "?organization_id=" + zohoOrganization;
var params = {
method: 'POST',
contentType: "application/x-www-form-urlencoded",
payload: {JSONString: Utilities.newBlob(JSON.stringify(invoice), "application/json")}, // or null instead of "application/json"
headers: {Authorization: "Zoho-oauthtoken " + zohoOauthToken},
muteHttpExceptions: true,
};
var response = UrlFetchApp.fetch(url, params);
console.log(response.getContentText());
Note:
I think that above modified request is the same with the sample curl command for "Create an invoice". But, if above modified script occurs an error, please try the following patterns.
Pattern 1:
For above modified script, please modify params as follows and test it again.
var params = {
method: 'POST',
payload: {JSONString: Utilities.newBlob(JSON.stringify(invoice), "application/json")},
headers: {Authorization: "Zoho-oauthtoken " + zohoOauthToken},
muteHttpExceptions: true,
};
Pattern 2:
For above modified script, please modify params as follows and test it again. From OP's test, it was found that this sample request was correct.
var params = {
method: 'POST',
contentType: "application/json",
payload: {JSONString: JSON.stringify(invoice)},
headers: {Authorization: "Zoho-oauthtoken " + zohoOauthToken},
muteHttpExceptions: true,
};
or
var params = {
method: 'POST',
contentType: "application/json",
payload: JSON.stringify(invoice),
headers: {Authorization: "Zoho-oauthtoken " + zohoOauthToken},
muteHttpExceptions: true,
};
References:
Create an invoice
fetch(url, params)
Added:
When OP tested my proposed scripts, OP said the working script is The first one under Pattern 2. In this case, it seems that the sample curl command at the official document is not correct. When The first one under Pattern 2 is converted to the curl command, it's as follows. In this sample curl command is from the top of my answer.
$ curl https://books.zoho.com/api/v3/invoices?organization_id=10234695
-X POST
-H "Authorization: Zoho-oauthtoken 1000.41d9f2cfbd1b7a8f9e314b7aff7bc2d1.8fcc9810810a216793f385b9dd6e125f"
-H "Content-Type: application/json;charset=UTF-8"
-F 'JSONString="{,,,}"'
The Google Apps Script is as follows.
var invoice = {
customer_id: '2298656000000277003',
invoice_number: 'MU001',
date: '2021-09-02',
line_items: [
{
item_id: '2298656000002380000',
name: 'Item1',
description: 'This is the description',
rate: '1500.00',
quantity: '2',
},
],
notes: 'These are the notes of this Invocie'
};
var zohoOauthToken = '###';
var zohoOrganization = '19012342064';
var baseUrl = "https://books.zoho.com/api/v3/invoices";
var url = baseUrl + "?organization_id=" + zohoOrganization;
var params = {
method: 'POST',
contentType: "application/json",
payload: {JSONString: JSON.stringify(invoice)},
headers: {Authorization: "Zoho-oauthtoken " + zohoOauthToken},
muteHttpExceptions: true,
};
var response = UrlFetchApp.fetch(url, params);
console.log(response.getContentText());

Related

How do we use wit.ai in a portfolio website on github pages?

How do i connect wit.ai api to my portfolio website?
tried this below code for fetching api, can we use api call in static website on github pages or i will have register for domain name and then develop seperately?
$("#submit-button").click(function() {
var userInput = $("#user-input").val();
var apiKey = "myapi";
$.ajax({
url: "https://api.wit.ai/message?v=20230129&q=",
type: "GET",
headers: {
"Authorization": "Bearer " + apiKey //curl \
//-H "Authorization: Bearer myapi" \
//"https://api.wit.ai/message?v=20230129&q="
},
data: {
"q": userInput
},
success: function(response) {
var intent = response._text;
var entities = response.entities;
//process the intent and entities to generate the chatbot's response
$("#chatbot-response").text(chatbotResponse);
}
});
});

Getting error while framing request URL using appscript

I am trying to frame request for API using appscript.
var url_string = "https://*.cognitiveservices.azure.com/vision/v3.2/describe"
let body = {
'"url"':'"https://www.khwaahish.com/wp-content/uploads/2022/01/khwaahish-white-bg-logo.jpg"'
};
const headers = {
'method' : 'POST',
'Host':'imagealttextcreation.cognitiveservices.azure.com',
'Content-Type': 'application/json',
'Ocp-Apim-Subscription-Key':'###',
'payload': body
};
var response = UrlFetchApp.fetch(url_string,headers)
Logger.log(response)
I am getting invalid request error. But the same thing is working when i try manually(attached image for same).
Am I missing something while forming this request in the appscript?
When tried manually using the browser the functionality works. i want help in correcting the request using appscript.
From the official document, in your script, how about the following modification?
Modified script:
var url_string = "https://*.cognitiveservices.azure.com/vision/v3.2/describe";
let body = { url: "https://www.khwaahish.com/wp-content/uploads/2022/01/khwaahish-white-bg-logo.jpg" };
const options = {
headers: { "Ocp-Apim-Subscription-Key": "###" }, // Please set your value.
payload: JSON.stringify(body),
contentType: "application/json"
};
var response = UrlFetchApp.fetch(url_string, options);
Logger.log(response.getContentText())
Reference:
fetch(url, params)

Issue sending in method to UrlFetchApp.fetch in GAS

Stupid question here, but I am pulling my hair out (i'm bald) as to what I could possibly be doing wrong. I am doing a UrlFetchApp.fetch in google app scripts:
var result = UrlFetchApp.fetch(url, { headers: headers });
When using this as my headers, it works:
var headers = {
Authorization: 'Bearer ' + getAccessToken()
}
Now I need to pass in 'method' as 'PUT' instead of the default of 'GET' (above), and and trying like this:
var headers = {
method : 'put',
headers : {
Authorization: 'Bearer ' + getAccessToken()
}
}
When I try sending this, it is not finding the token:
Exception: Request failed for https://api.spotify.com returned code 401. Truncated server response: {
"error": {
"status": 401,
"message": "No token provided"
}
How can I format the headers so that I can pass in the Authorization with token and also pass in 'method' as 'PUT'?
I see in the URLFetchApp.Fetch documentation for Google, that this is passed into options:
https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app
headers Object a JavaScript key/value map of HTTP headers for the request
method String the HTTP method for the request: get, delete, patch, post, or put. The default is get.
Thank you so much for any help!
phi
I believe your goal is as follows.
You want to convert the following curl command to Google Apps Script. Ref And, from I know the call works with a simple GET method, your access token is valid.
curl --request PUT \
--url https://api.spotify.com/v1/me/player/play \
--header 'Authorization: ' \
--header 'Content-Type: application/json' \
--data '{
"context_uri": "spotify:album:5ht7ItJgpBH7W6vJ5BqpPr",
"offset": {
"position": 5
},
"position_ms": 0
}'
In this case, how about the following sample script?
Sample script:
Please modify data for your actual situation.
var data = {
"context_uri": "spotify:album:5ht7ItJgpBH7W6vJ5BqpPr",
"offset": {
"position": 5
},
"position_ms": 0
};
var options = {
method: 'put',
headers: { "Authorization": 'Bearer ' + getAccessToken() },
contentType: "application/json",
payload: JSON.stringify(data)
};
var url = "https://api.spotify.com/v1/me/player/play";
var res = UrlFetchApp.fetch(url, options);
console.log(res.getContentText());
Note:
I think that this request is the same as the curl command. But if an error occurs, please check the access token and the values in data, again.
References:
Start/Resume Playback
fetch(url, params)

How can I send authentication token in header of a POST request from Django Template

I have an API call working fine on:
curl -H "Content-Type: application/json" -H "Authorization: Token d070b44498fd12728d1e1cfbc9aa5f195600d21e" http://localhost:8000/api/subscribers/
It gives me the list of all subscribers. I want to create a Django template to send the request to subscribers. I am not able to send:
-H "Authorization: Token d070b44498fd12728d1e1cfbc9aa5f195600d21e"
from my template.
import requests
headers={'Content-Type':'application/json', 'Authorization':'Token d070b44498fd12728d1e1cfbc9aa5f195600d21e'}
r = requests.get('http://localhost:8000/api/subscribers/', headers=headers)
Why don't you use AJAX to send this? Call the JS function whenever you want to make the request.
$.ajax({
type: "POST",
url: url,
headers: {
'Token': 'your_token_here'
},
data: {
'body': 'value'
}
}).done(function (data) {
console.log("API call successfull : ", data);
});
Ajax is one of the simple ways to do an API call from django template.
See the example below.
$.ajax({
type: 'GET',
url: 'http://localhost:8000/api/subscribers/',
headers: {'Authorization': 'Token d070b44498fd12728d1e1cfbc9aa5f195600d21e'},
success:function(response) {
// on success
},
error: function() {
// on error
}
});
In angularJs we can call API using $http. See the example below,
$http.get("http://localhost:8000/api/subscribers/",
{headers: {'Authorization': 'Token d070b44498fd12728d1e1cfbc9aa5f195600d21e',
'Content-Type':'application/json'}
}).then(function(response) {
// on success
},
function(data) {
// on error
});

Upload a file but set Content-Type

I got Watson Speech-to-Text working on the web. I am now trying to do it on react native but am getting errors on the file upload part.
I am using the HTTPS Watson API. I need to set the Content-Type otherwise Watson returns a error response. However in react-native, for the file upload to work, we seem to need to set 'Content-Type' to 'multipart/form-data'. Is there anyway to upload a file in react-native while setting Content-Type to 'audio/aac'?
The error Watson API gives me if I set 'Content-Type': 'multipart/form-data' is:
{
type: "default",
status: 400,
ok: false,
statusText: undefined,
headers: Object,
url: "https://stream.watsonplatform.net/speech-to-text/api/v1/recognize?continuous=true",
_bodyInit: Blob,
_bodyBlob: Blob
}
The response body is:
{
"code_description": "Bad Request",
"code": 400,
"error": "No JSON object could be decoded"
}
Here is my code (full code is here - gist.github.com ):
const ext = 'aac';
const file_path = '/storage/emulated/0/Music/enter-the-book.aac';
data.append('file', {
uri: `file://${file_path}`,
name: `recording.${ext}`,
type: `audio/${ext}`
}, `recording.${ext}`);
const response = await fetch('https://stream.watsonplatform.net/speech-to-text/api/v1/recognize?continuous=true', {
method: 'POST',
headers: {
// 'Content-Type': `audio/${ext}`,
'Content-Type': 'multipart/form-data',
'X-Watson-Authorization-Token': token
},
body: data
});
console.log('watson-stt::getResults - response:', response);
if (response.status !== 200) {
const error = await response.text();
throw new Error(`Got bad response "status" (${response.status}) from Watson Speach to Text server, error: "${error}"`);
}
Here is a screenshot of the error I get when I set 'Content-Type': 'audio/aac':
Thanks so much to DanielBolanos and NikolayShmyrev this is the solution I used:
This code is for iOS so I recorded the audio as blah.ulaw BUT the part_content_type is aduio/mulaw;rate=22050 this is very important to use mulaw even though file ext is ulaw. An interesting note: I couldn't play the blah.ulaw file on my macOS desktop.
Also note that you MUST NOT set Content-Type to multipart/form-data this will destroy the boundary.
Also Bluemix requires rate in the part_content_type for mulaw
const body = new FormData();
let metadata = {
part_content_type: 'audio/mulaw;rate=22050' // and notice "mulaw" here, "ulaw" DOES NOT work here
};
body.append('metadata', JSON.stringify(metadata));
body.append('upload', {
uri: `file://${file_path}`,
name: `recording.ulaw`, // notice the use of "ulaw" here
type: `audio/ulaw` // and here it is also "ulaw"
});
const response = await fetch('https://stream.watsonplatform.net/speech-to-text/api/v1/recognize?continuous=true', {
method: 'POST',
headers: {
// 'Content-Type': 'multipart/form-data' // DO NOT SET THIS!! It destroys the boundary and messes up the request
'Authorization': `Basic ${btoa(`${USERNAME}:${PASSWORD}`)}`
},
body
});
According to the documentation for multipart requests the request should be:
curl -X POST -u "{username}":"{password}"
--header "Transfer-Encoding: chunked"
--form metadata="{
\"part_content_type\":\"audio/flac\",
\"timestamps\":true,
\"continuous\":true}"
--form upload="#audio-file1.flac"
"https://stream.watsonplatform.net/speech-to-text/api/v1/recognize"
So the content-type should be multipart/form-data, you can specify aac as "part_content_type": "audio/aac".
The big problem you have is that audio/aac is not in supported formats. You might probably need another codec.