Using Zoho’s CRM Version 2 PHP SDK API with OAuth

A year or two ago I did some work for a client with the Zoho API version 1.0. Now, they’ve deprecated that API version and will stop supporting it soon, so I must upgrade to version 2 of the API.

Version 2.0 of the Zoho API uses OAuth for authentication which is not something I have used often, if ever. The API’s I’ve worked with in the past may have had an OAuth option, but usually, there was another option available if using the API for ourselves with our own account. In other words, I am not writing a plugin to be used by multiple clients with different login information. This is custom code for one client to be used to integrate their website with their zoho account.

I had a hard time getting the authentication to work, so I thought I would write about what I found to work in the end. Hopefully, this will save someone else some time.

I decided to use the PHP SDK to take advantage of the persistence handler

I was going to use the PHP SDK at first, but I don’t have a lot of work to do with this API. I just need to insert a couple of leads and vendors and pull some emails from their current contacts, so learning the SDK when seemed like overkill. I am usually pretty good at learning API’s using JSON or XML.

However, once I finally figured out how to do OAuth using the API without the SDK, I realized that I would have to write a lot of code to handle the persistence of the grant, access and refresh tokens. I decided to use the PHP SDK just to take advantage of their persistence handler.

I decided to use the file handler instead of a database for persistence

Since I don’t have a lot of users and I didn’t want to set up another database for my clients site, the file seems to be our best option. The database seemed like overkill just to handle the access and refresh tokens.

To make this work correctly, I had to create a persistence file named zcrm_oauthtokens.txt and leave it empty (it’s important that it’s named exactly that). I could not get it to work until I created this empty file.

Setting up the configuration file

There are two configuration files in the SDK. The first is

I first set the sandbox to true, but this didn’t work well for me. Not sure why, but the code only worked when setting this to false.

I created the application log file by creating a ZCRMClientLibrary.log and then putting the path to that file in the configuration file. I haven’t gotten anything to show up in this file yet, but I’ll update this post when and if I do. Maybe I have this setup incorrectly?

You need to set the currentUserEmail to the email address of the user email of the Zoho account that’s used for creating the grant token.

My configuration file looks like this:

The other configuration file is the file in the same location as the first configuration file. These are in the vendor/zohocrm/php-sdk/src/resources folder.

The oauth_configuration file needs to have the client_id and the client_secret from the zoho developer console where you set up the app. This is documented fairly well in the zoho api documentation.

The redirect_uri in the configuration file should match the redirect_uri used on the developer console app setup as well and should be the name of the script that will be making the api calls.

The token_persistence_path should be the path to the new file you created without the file name – just the path.

The access_type should be offline and the persistance_handler_class should be ZohoOAuthPersistenceHandler.

My file looks something like this:


Getting my Access and Refresh Tokens

The Access and Refresh tokens only need to be gotten once per user and since I’m the only user, then I only have to do this once to add the tokens to the zcrm_oauthtokens.txt file.

Here is the code I used to get these tokens:

	$oAuthClient = ZohoOAuth::getClientInstance();
	$grantToken = "{grant token goes here}";
	$oAuthTokens = $oAuthClient->generateAccessToken($grantToken);

The grant token can be gotten by either using the self-client in the developer console or going to the specific url listed in the documentation. Take note that the grant token will only last for 3 to 10 minutes depending on what you select when you use one of these methods. So, once you’ve got the grant token, you must insert it into your code and run the code to create the zcrm_oauthtokens.txt file within that small time frame. If you miss the time frame, you may have to delete the contents of that file (if there are any) and start over. This will not work if there is information already in that file, it will give an error. Or at least, that was my experience.

To use the self-client or the url, you will need to know the scope of access that you will need. For my testing, I wanted to give myself permission to everything. I used the self-client to produce my grant token. Through trial and error I finally figured out that I should have the scope set to this:


Notice that there are NO spaces in that line. When I put spaces after the commas, nothing happened when I clicked the button.

I set the self-client to the scope above and then gave myself 10 minutes, just in case things didn’t go as expected. Make sure the zcrm_oathtokens.txt file is empty, but there. then run the script. For me, nothing happened. I got a blank screen, however, the very first time, it took me to a zoho web page that asked me to accept the access to my account. Every time after that, I only got a blank screen. I’m sure that’s because I didn’t have any code yet in my script where the redirect_url was returning the call.

Once the script had finished, I looked at my zcrm_oathtokens.txt file and saw a serialized array that did, indeed, have my tokens in there along with my email address. Success!

Next I ran the sample code from one of the version 2.0 API examples and got the expected results!

    foreach ($moduleArr as $module) {
        echo "ModuleName:".$module->getModuleName();
        echo "SingLabel:".$module->getSingularLabel();
        echo "PluLabel:".$module->getPluralLabel();
        echo "BusinesscardLimit:".$module->getBusinessCardFieldLimit();
        echo "ApiName:".$module->getAPIName();
        if($fields==null) {
        foreach ($fields as $field) {
            echo $field->getApiName().", ";
            echo $field->getLength().", ";
            echo $field->IsVisible().", ";
            echo $field->getFieldLabel().", ";
            echo $field->getCreatedSource().", ";
            echo $field->isMandatory().", ";
            echo $field->getSequenceNumber().", ";
            echo $field->isReadOnly().", ";
            echo $field->getDataType().", ";
            echo $field->getId().", ";
            echo $field->isCustomField().", ";
           echo $field->isBusinessCardSupported().", ";
          echo $field->getDefaultValue().", ";
} catch (ZCRMException $e) {
    echo $e->getCode();
    echo $e->getMessage();
    echo $e->getExceptionCode();

I would love to hear about your experience with the API in the comments below. If you need help with the API, please contact me.

22 thoughts on “Using Zoho’s CRM Version 2 PHP SDK API with OAuth”

    1. You are welcome. I’m glad it helped.

      I have to warn you that I had to quit using their version 2 API because it wouldn’t let us do everything the v1 API let us do, specifically placing the leads in the correct modules. I believe the version 2 is a step backwards unfortunately.

      We ended up having to iframe the zoho forms into the site so that we had more control over where to input the information. 🙁

  1. just popping in to say another big thank-you – wouldn’t have got this done without your post 🙂

    I’m very new to APIs so apologies for any misunderstandings but just a few notes on my experience, to help anyone else:
    * I followed your approach, but used the Python SDK in Windows 10
    * I found I didn’t need to create ‘zcrm_oauthtokens.txt ‘ as the script created a ‘zcrm_oauthtokens.pkl’ file in the specified persistence directory
    * Just to add on to your post, I believe there is one more chunk of code you need to run each time you want to use the API (e.g. the next day), because the Access token expires after an hour.

    # 1 – First chunk of code to run – you only ever need to run this once, to generate the refresh token file (lives in the specified persistence directory). This is the same code as Cindy has specified:
    oauth_client = zcrmsdk.ZohoOAuth.get_client_instance()
    grant_token = “INSERT YOUR GRANT TOKEN HERE”
    oauth_tokens = oauth_client.generate_access_token(grant_token)

    # 2 – Run this chunk of code (in isolation from the above chunk) to generate/update the access token using the refresh token – necessary because the access token apparently expires every 1 hour:
    oauth_client = zcrmsdk.ZohoOAuth.get_client_instance()
    refresh_token = “INSERT YOUR REFRESH TOKEN HERE”
    oauth_tokens = oauth_client.generate_access_token_from_refresh_token(refresh_token,user_identifier)

    # 3 – So now you have your refresh token and you have used it to create/update your access token, now for the next hour your access token should be un-expired, so the only code you need to run this the below, followed by your queries:

    Hope this helps

    1. Great info Kev! Thank you! I have not had to refresh the tokens for access, HOWEVER, we had to quit using Version 2 of the API because Zoho does not treat the information the same as it did version 1 and our submissions were not going to the desired locations in Zoho.

      I have not been impressed with their support team. Their answer was pretty much, “Too bad, that’s how it works” even though it does not allow you to choose where you upload the information.

      For instance, my client wanted the information stored in the ‘to be approved’ leads section, but we could not make it show up there. Their answer was that you have to upload a CSV file to make that happen.

      We ended up using a zoho form and iframing it into the page and then using their Workflows to send out the appropriate emails. Not optimal, but about all we could do according to their support.

      I’m not a Zoho fan.

      1. right, that sounds pretty frustrating! Having a poke around on various forums, I can see a number of other users quite frustrated with the support team also – frustrations around insufficient or inaccurate documentation amongst other things. I’m too green to know the good from the bad so far 🙂
        Thanks again for the write-up!

  2. Hi, I’m little confused about following points:
    1.Can you please explained me what we will do after creating zcrm_oauthtokens.txt file to check total persistence path and log path is correct

    1. Rohit, the authtokens are used by the sdk to authenticate your API session I believe. As for the total persistance path and the log path, you will need to check your set up to see where the SDK is looking for those and then make sure that’s where those files are located.

    I am new to APIS and followed the indicated steps. However, I generated an error at the beginning: (Offset not defined: 1) after changing (sandbox = true) to (sandbox = false). I generated the error: (Index not defined: name) and I have no idea what it could be. I hope you can help me. I would appreciate it enough.

    and I’m sorry my english is not very good.Thank you

    1. I would need to see your code to help. Usually that error means you have $var[‘name’] being used but it doesn’t exist in the array. If you’ll post your code, I can help you figure it out.

  4. I was trying to add V2 Api from couple of days but did not reach to output. Finally, I done this.
    Thank you for this article. It helps a lot.

  5. Hi, may i know if did you explicitly create the files? I can’t seem to find these in src folder.


    1. Hi Emmanuel,

      To be honest, I don’t remember if I created the file manually or if it was created for me somehow. But, here is a copy. I found it in the vendor/zohocrm/php-sdk/src/resources/ folder, in the file:

  6. Hi Cindy,
    I am using the PHP SDK to connect with Zoho, but I get the error:
    No Tokens exist for the given user-identifier,Please generate and try again.’ in /vendor/zohocrm/php-sdk/src/oauth/persistence/ZohoOAuthPersistenceByFile.php

    Did you get this issue? Could you please share your success connected code?


    1. I did at first, but following the directions in the blog post about getting the token the first time, solved it for me.

    1. Hi Eric, This is all I have for Zoho:

      Turns out their API v2 has a lot to be desired, in my opinion. Version was much better. The V2 won’t let us add leads the way we could in V1. So, we’ve tried to use workflows inside Zoho as much as possible instead of using the API.

  7. I am facing an unusual issue in zcrm_oauthtokens.txt file. SDK is not able to read from this file. Because serialized data in this file is not correct. It has inserted NUL at many places. Plz check screenshot.
    I am using it in laravel.
    How can I get rid of from this issue.

    1. Just adding a note here for anyone who encounters the above, I found the same using Symfony, however the NUL values don’t seem to stop functionality working, so seem safe to ignore and let their SDK manage the persistence.

  8. hello Sir,
    step1. add client id.
    step2. for self client generate code
    step3. make post string to generate refresh token
    step4. install sdk
    in last i am getting following error while fetching access token from refresh token……….
    Fatal error: Uncaught zcrmsdk\oauth\exception\ZohoOAuthException Caused by:’zcrmsdk\oauth\exception\ZohoOAuthException Caused by:’Exception while fetching access token from refresh token – HTTP/1.1 200 Server: ZGS Date: Sun, 09 Feb 2020 03:29:00 GMT Content-Type: application/json;charset=UTF-8 Content-Length: 26 Connection: keep-alive Set-Cookie: b266a5bf57=a711b6da0e6cbadb5e254290f114a026; Path=/ X-Content-Type-Options: nosniff X-XSS-Protection: 1 Set-Cookie: iamcsr=0f10f944-fe15-4831-bc8c-6ecc12384d12;path=/;Secure;priority=high X-Frame-Options: SAMEORIGIN Strict-Transport-Security: max-age=63072000
    in F:\\vendor\zohocrm\php-sdk\src\oauth\ZohoOAuthClient.php(100) #0 F:\\vendor\zohocrm\php-sdk\src\oauth\ZohoOAuthClient.php(78): zcrmsdk\oauth\ZohoOAuthClient->refreshAccessToken(‘1000.9027d85cdb…’, ‘contact@futured…’) #1 F:\\index.php(28): zcrmsdk\oauth\ZohoOAuthClient->generateAccessTokenFromRefresh in F:\\vendor\zohocrm\php-sdk\src\oauth\ZohoOAuthClient.php on line 103

    i have repeated it too many times and every time the same error “invalid client”
    this error is in my new zoho account, while i have another account where its working fine…

    can you help me what the error i am doing…

    1. Hi there, Check that you have the correct credentials in your configuration file for the account you are trying to get in. Also make sure the email address in the configuration file matches the account owner of the Zoho account. Hope that helps!

    2. Hi Tarun

      I am sure you sorted this out, however I had this same issue and the fix I needed was to ensure that all regions are set correctly, the SDK has some internal values that default to the US region, however I created a Self Client in the EU region.

      As I’m setting my values through their SDK object constructors like so with an array:

      Important values to set in the configuration array were as follows and should match the region you use when creating your Self Client (or whichever you choose in their Developer Console)

      ‘accounts_url’ => ‘’
      ‘apiBaseUrl’ => ‘’

      Hope that helps someone.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top