Since 2020, Zoho has deprecated its old API v1 in favor of API v2 that features OAuth2 for authentication. This has made both newcomers and veteran users search for solutions to quickly and effortlessly implement this new protocol.
The sad thing about it is that even though Zoho is one of the most popular and complete CRM suites out there, their documentation leaves a lot to be desired, just looking at the README.md
of Zoho’s PHP SDK official repository in Github makes you cringe, someone copy-pasted it in there and ran away. Same bad luck when searching for the documentation online, scattered on several outdated pages, sections and forums, where desperate developers ask for help after hours of frustration. More often than not, Zoho employees take up to three weeks to reply and in some cases don’t even know what they’re talking about, in some cases other users had to correct them…
So before you waste a dozen hours trying to figure out the most effective and less time-consuming way to integrate your system with Zoho’s incomplete and rushed API v2 in PHP, here’s how I did it.
What you’ll get after reading this article
You will be able to use the API v2 via REST/JSON, without using their SDK, which I found complicated and couldn’t get it to work, encountering several errors from which I couldn’t find any troubleshooting info online. And this was from an out of the box Ubuntu server LAMP setup so 99% chance it wasn’t my server’s fault.
In all fairness, their REST API is pretty well done, easy to use, and the documentation for it is great. So no need to learn just another SDK.
I will be simplifying the code so it’s easy to read and adapt to your framework, please create your own components and methods once you understand the whole structure and process.
Authenticating in Zoho API v2 via PHP
There’s a few things you are going to end up with, probably storing them in your $params
:
- Client ID and Client Secret: Needed to generate the Refresh Token.
- Redirect URI: A URL in your server that can receive a callback, I haven’t needed it really, so any URL in your domain works.
- Self client Token: Needed once to generate the Refresh Token, expires after just 10 minutes so you’ve got to be quick.
- Refresh Token: Never expires, used to request an Access Token.
- Access Token: Used to make requests to the API, expires after 1 hour and you can get a new one with the Refresh Token.
Client ID and Client Secret
Read the entirety of this part before doing anything, one of the tokens given here will expire in 10 minutes and you will need to start again.
Depending on where your data is hosted, you will need to access one of these URLs:
- https://accounts.zoho.com/developerconsole
- https://accounts.zoho.eu/developerconsole
Click on “Add Client ID” and grab the Client ID and the Client Secret, save it somewhere.
Self client Token
Then click on the three dots at the end and choose “Self client“.
In the Scope field type this:
aaaserver.profile.READ,ZohoCRM.users.ALL,ZohoCRM.modules.ALL,ZohoCRM.settings.all
You can see the full list of scopes here, if you change them, remember to separate scopes with a comma and no spaces and include the aaaserver.profile.READ
at the beginning. Otherwise it may fail with silent errors and blank pages and you’ll spend some time pulling your hair.
For Expiry choose 10 minutes so we have enough time.
This will give us the Self client token which expires in 10 minutes so let’s be quick.
Refresh Token
Now we need to make a POST request to this URL (choose one depending on your location):
- https://accounts.zoho.com/oauth/v2/token
- https://accounts.zoho.eu/oauth/v2/token
I used Postman for this since it’s a one time request and it made no sense to implement this step into my code.
The request must include the following Header:
Key | Value |
---|---|
Content-Type | application/x-www-form-urlencoded |
And a Body (x-www-form-urlencoded
) with:
Key | Value |
---|---|
code | 1000.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
redirect_uri | https://www.yourdomain.com/callback |
client_id | 1000.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
client_secret | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
grant_type | authorization_code |
Change all the above fields with your details except for the grant_type
.
code
is the Self client code you got before, the one that expires. You have 10 minutes to make the request or else generate a new one.
This will give us the Refresh Token in a JSON response, it never expires so once you get here, congrats!
Access Token
Now we make a similar request to Zoho’s token endpoint:
- https://accounts.zoho.com/oauth/v2/token
- https://accounts.zoho.eu/oauth/v2/token
But replacing grant_type
 with refresh_token
and removing redirect_uri
in the Body:
Key | Value |
---|---|
refresh_token
|
1000.xxxxxxxxxxxxxxx.xxxxxxxxxxxxxxxxxx |
client_id | 1000.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX |
client_secret | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
grant_type |
refresh_token
|
This will give us the Access Token that we will use for our REST calls, and the Expires In.
It is a good idea and good practice to store both access_token
and expires_in
somewhere, either in a Database or in an internal file so you don’t need to request a new Access Token every time (it takes ~4 seconds to generate and Zoho may limit the number of Access Tokens you can generate repeatedly). Also, when checking the expiry date, subtract a minute or two to be safe.
API Requests in Zoho API v2 via PHP
The hard part is over, now comes the requests to Zoho’s REST API which is pretty standard.
Endpoints are as follow:
- https://www.zohoapis.com/crm/v2/
- https://www.zohoapis.eu/crm/v2/
And the Headers should include the Access Token:
Key | Value |
---|---|
Authorization
|
Zoho-oauthtoken ACCESS_TOKEN
|
The documentation for the REST API is well written, all in one page and includes examples so I won’t be rewriting everything, check it out here.
Contacts and Leads are explained in the Records API section, you simply type Contacts
or Leads
in the URL.
Find a Contact by its email address
Here’s a quick example on how to find a Contact by its email address:
$endpoint = 'https://www.zohoapis.eu/crm/v2/'; $email = '[email protected]'; $url = $endpoint.'Contacts/search?criteria='.rawurlencode('(Email:equals:'.$email.')');
Update/Upsert/Insert
Note that when making Updates/Upserts/Inserts, the info needs to be inside a data
array and JSON-encoded:
$post_data = json_encode([ 'data' => [ 'Last_Name' => 'Griffin', 'Email' => '[email protected]', ] ]);
Also note that fields are case-sensitive so very prone to mistakes.
Summing up
So that pretty much wraps everything up, you will get a nice and simple integration with Zoho’s API v2 and you don’t even need their SDK, saving some resources and tons of potential bugs. I am quite happy to be able to deal with the REST API since it’s something you are used to when working with other third parties, instead of having to learn a new SDK and all their methods and outputs.
2 comments
Mukund says:
I tried exactly, but getting “invalid client”
Alberto says:
Gracias por la guÃa, todo muy bien explicado :D