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());
What is the equivalent axios request for cURL request below?
curl -X POST \
http://159.89.90.5:5000/users/login \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
-d '{
"email": "pwerner#gmail.com",
"password": "password"
}'
I've tried using axios request as follow:
let axiosConfig = {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
}
};
this.$http.post('http://159.89.90.5:5000/users/login', {"email": "pwerner#gmail.com", "password": "password"}, axiosConfig)
.then(response => {
console.log(response)
}).catch(function (error) {
console.log(error);
currentObj.output = error;
});
but I keep getting CORS error because the request doesn't fit with the request I made in cURL above. What am I missing here? if correct like curl request above I'll get email parameter with value pwerner#gmail.com
below is the error I've got when trying to make the request:
but if I use formData instead of using json for the same code, it works, and my server (flask framework) is already provided header: response.headers.add("Access-Control-Allow-Origin", "*") for solving CORS issue
I'm developing a react native application that combines a Photon Particle.
By following the documentation of a Two legged auth; before configure a device I need to get a claim code.
curl -X POST \
https://api.particle.io/oauth/token \
-H 'Accept: application/json' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=client_credentials&client_id=client_id&client_secret=clsecret&scope=customer%3Demail%40gmail.com'
When I do the request using CURL or even postman I got the desired results. But when I tried this using axios inside react native (iOS), I'm always getting the following error: Invalid or missing grant_type parameter.
The code below is my React Native code that is retrieving the data. And as you can see, I'm passing the grant_type.
costumerToken() {
const route = `${this.route}/oauth/token`;
const headers = {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded"
}
const body = {
"grant_type": "client_credentials",
"client_id": this.clientId,
"client_secret": this.clientSecret,
"scope": `customer=${this.costumerEmail}`
}
console.log(route, headers, body);
return axios.post(route, body, {headers: headers})
.then(res => {
return Promise.resolve(res);
})
.catch(err => {
return Promise.reject(err.response);
});
}
What is wrong?
When passing an Object as axios.post() body, it will send it as JSON but the Particle API expect it to be application/x-www-form-urlencoded. Axios docs go more deeply into this topic. To make it work you could change the code to:
customerToken() {
const route = `${this.route}/oauth/token`;
const headers = {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded"
}
const body = new URLSearchParams();
body.append("grant_type", "client_credentials");
body.append("client_id", this.clientId);
body.append("client_secret", this.clientSecret);
body.append("scope", `customer=${this.costumerEmail}`);
console.log(route, headers, body);
return axios.post(route, body, {headers: headers})
.then(res => {
return Promise.resolve(res);
})
.catch(err => {
return Promise.reject(err.response);
});
}
I have a backend that performs BASIC authentication. I am passing the username/password encoded in curl as follows
curl -D- -X GET -H "Authorization: Basic cmFtcmFtOnBhc3N3b3Jk" -H "Content-Type: application/json" "http://localhost:9000/users/login"
and It works fine
Whereas in vue.js using vue-resource I am trying to do the same using
var options = {
url: 'http://localhost:9000/users/login',
method: 'GET',
headers:
{
'Authorization': 'Basic cmFtcmFtOnBhc3N3b3Jk'
}
}
context.$http(options).then(res => {
if (res.ok) {
cb({ authenticated: true })
} else {
cb({ authenticated: false })
}
})
But it is not getting authenticated. The request information i got from devtools is as follows
Accept:*/*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-GB,en;q=0.8,fr;q=0.6,en-US;q=0.4
Access-Control-Request-Headers:authorization
Access-Control-Request-Method:GET
Connection:keep-alive
DNT:1
Host:localhost:9000
Origin:http://evil.com/
Referer:http://localhost:8080/Login
I do not see the authorization information being passed to the server. Am i doing something wrong ? Note : Both server and client are on localhost.
Thanks
vue-resource is retired so I don't think you should use it anymore. Instead, how about you use fetch instead as suggested and see if it works:
fetch('http://localhost:9000/users/login', {
method: 'POST',
headers: new Headers({
'Authorization: Basic cmFtcmFtOnBhc3N3b3Jk',
'Content-Type': 'application/json'
}),
body: JSON.stringify(req.body.payload)
})
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
});