0

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:

  1. Created a Self-Client in Zoho API Console to generate a Client ID and Client Secret
  2. Generated an authorization code for all Scopes under Invoices in the Zoho API Console
  3. Generated an access token and refresh token - using Postman
  4. 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?

1 Answers1

0

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:

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());
Tanaike
  • 181,128
  • 11
  • 97
  • 165
  • Thank you Tanaike. While Pattern 2 in the above code worked in terms of authentication. There seems to be a problem now with Zoho Books itself. On running the code, I am getting the error, `{"code":6024,"message":"This user belongs to multiple organizations, hence the parameter CompanyID/CompanyName is required for associating this user to a specific organization."` – Mohit Baid May 06 '21 at 06:07
  • @Mohit Baid Thank you for replying. I have to apologize for my poor English skill. Unfortunately, from your replying, I cannot understand about your current situation. So, I would like to confirm my understanding of your replying. In your current situation, the authorization process worked using my modified script. But, the request after the authorization didn't work because of the issue of Zoho Books itself. Is my understanding correct? – Tanaike May 06 '21 at 06:16
  • Yes. That's correct. The response received on running the script is {"code":6024,"message":"This user belongs to multiple organizations, hence the parameter CompanyID/CompanyName is required for associating this user to a specific organization." – Mohit Baid May 06 '21 at 06:38
  • @Mohit Baid Thank you for replying. In that case, I would like to recommend to contact to the manager of the API. I deeply apologize for this. But, I would like to leave my answer because the script for the authorization process, that you confirmed that it worked, might be useful for other users. I thought that when your new issue due to the API was resolved, the script might be able to be worked. – Tanaike May 06 '21 at 06:42
  • 1
    Turns out we missed an "=" after the organization_id in the url. – Mohit Baid May 10 '21 at 09:24
  • @Mohit Baid Thank you for replying. Yes. I could understand it. And, I apologize for this. So, I updated it. By the way, in that case, what pattern in my answer could your issue be resolved? I would like to know about it for my studying. – Tanaike May 10 '21 at 12:00
  • The first one under Pattern 2 – Mohit Baid May 11 '21 at 07:19