Step-by-step Example

This example is to show you how to get tokens from your account.

Let’s take a look at the full process of getting access to data, starting from the registration of a new integration. We will consider working directly with the authorization API, but you can use premade libraries to simplify development.

We developed the authorization on the base of the OAuth 2.0 protocol, that’s why you can find in open source a lot of examples and documentation, that describes the logic of making requests.

The contents of this page are:

1. Registration of an integration

2. Getting an authorization code

3. Exchange of the authorization code to access token and refresh token

4. Getting a new access token once it expires

5. Requests to API by exchanging an access token

6. Hook to disable integration

7. Errors handler

1. Registration of an integration

Integrations are used to enable your application/service to send requests to the API of Kommo.

The first step is to go to Settings, Integrations of the account, in which you will support the integration in the future.

Settings -> Integrations -> Create Integration

foto

Please note:

  • To create an integration, you need to have account administrator rights.
  • Integration will be assigned to this account. This means that any of the administrators of this account will be able to manage the integration and will have access to its shared keys. You can read more about the concepts. Such an account will be treated by us as a developer account.
  • If you are developing a public (marketplace) integration, you need to familiarize yourself with the requirements.

After clicking on the Create Integration button, a form appears containing the integration properties.

Integration Settings:

  • The name of the integration (no more than 255 characters) is displayed on the integration page, a modal window for granting access, and also participates in the search on the integration page.
  • Integration description (no more than 65,000 characters) is displayed in the modal integration window in the user account. It is allowed to use HTML layout.
  • The redirect link is a link to your site that will handle the work with tokens (or keys). It is important that the domain must be protected by an SSL certificate if you plan to use integration in more than one account. We also periodically check the availability of the domain as a prerequisite for the integration to work.
  • The link is for a hook about disabling integration. A GET request will be sent to this address when the user disables integration. The request will contain 2 parameters: account_id and client_id. The field for the disconnect hook is optional.
  • Grant access is the minimum set of necessary permissions for integration to work. You can read more about permissions.
  • Integration icon (400×272 jpeg/jpg/png/gif) is displayed in the list of integrations, and in the window for getting access from the user.
  • Duplicate control: you need to check this box if your integration supports Duplicate Control.
  • Multiple sources: you need to check this box if your integration manages the sources itself via sources API. If the box is checked, Kommo will not create sources by default, the integration itself will have to create all the sources it needs.

After filling out the form, save the integration. Kommo will generate and will show necessary keys in the keys and scopes tab. You will use the authorization code in the authorization process. Secret key and Integration ID will be used independently from the account, in which it will be installed.
Please note: The Secret key and Integration ID are linked to the integration, and will only be shown in your developer account.

2. Getting an authorization code

Let us remind you that the authorization code has a limited lifespan (20 minutes), and it’s required to get a pair of access and refresh tokens before its lifespan runs out. It’s available in the interface or via the Redirect URI if authorization has passed through the modal access window. This code is not hidden, which means that the user can see it in server requests. That’s why it has a limited lifetime, and within the framework of the OAuth 2.0 protocol, it must be exchanged for refresh and access tokens, using the keys of the integration that are known only to you.

You can get the Authorization code in three ways:

  1. Copy it from the modal window of the installed integration. This will work if you need to integrate only one account of Kommo. Jump to the next step.
  2. If your integration has a widget, then after installing it you will have a webhook sent to the Redirect URl
  3. Get the code after the user gets redirected to the Redirect URl

You can simplify development when getting a key via GET-parameters with Kommo button on the site.

The full logic on how to get an authorization code via GET-parameters is explained below:

  • Generate the link for users to go to. You need to send a user to URL https://www.kommo.com/oauth?client_id={Integration ID}&state={parameter of the state that will be sent to you to Redirect URl}&mode={popup or post_message}.
    Integration ID is already known to you from the modal window of the installed integration.
    The state parameter is generated by your string parameter, maybe your hash. State is needed so that when you receive a response from Kommo, you can verify its validity by comparing the sent token and the resulting one to make sure there is no CSRF substitution.
    The mode parameter is responsible for processing the request to the Redirect URI. In the popup method, the authorization window will be closed, and the transition to the Redirect URI will be performed in the main window. If the post_message value is passed, the redirection will occur in the window that was opened. After processing the authorization code, you need to close the window.
    Also, you can display information about the status of the action in the main window using the method postMessage.
  • The user on your site will open the link that you sent to them.
    Attention: It’s really important that for the user the whole process is understandable. When users click on the link, they need to understand that the request of the permissions will happen in their Kommo account and they need to understand which integration they are trying to install.
    That’s why we suggest using our branded button on the site.
  • By clicking on the link, the user will see the logo of your integration, that you uploaded when creating it, its name and the list of permissions which the integration requires.
    We suggest that such pages should be opened as a modal window, in popup. This will allow users not to lose the context of the page, which opened the popup.
  • If the user is not authorized, they will be asked to authorize in Kommo. Otherwise, they will be able to choose from accounts where they are the administrator. For private integrations, the list will be limited to one account.
  • After selecting an account and clicking on the button Allow, the integration will be installed in the selected account and the user will be redirected in modal or in the main window, depending on the parameter mode. They will be redirected to the Redirect URl that you indicated on the setup stage of the integration, with GET-parameters: code, referrer, state, from_widget.
    Parameter code has Authorization code, parameter referer represents the address of the account user, parameter state is the string that you passed when opening the window. If no string was passed, this parameter will not be returned. If we send a webhook after installing the widget, then you will additionally receive the GET parameter from_widget.
    {Redirect URl}?code=XXX&state={state}&referer={subdomain}.kommo.com&client_id={Integration Id}
    
  • In case if the user clicks on the button Decline, he will be redirected to the Redirect URl with GET-parameter error=access_denied, and with GET-parameter state, if it was sent before.
    {Redirect URl}?error=access_denied&client_id={Integration Id}&state={state}

Example of processing authorization, if a parameter post_message was sent

When passing the GET-parameter mode with value post_message in the window to allow access, the redirect will happen in the same window. Below we will discuss examples of interaction between the modal window to allow access and the main window using the postMessage function.

The code below is from the main window:

var popup;

auth();

// 1. Opens window to grant access
function auth() {
  popup = window.open('https://www.kommo.com/oauth?client_id=XXX&state=XXX&mode=post_message', 'Allow Access', 'scrollbars, status, resizable, width=750, height=580');
}

// 2. Registering a message handler from the popup window
window.addEventListener('message', updateAuthInfo);

// 3. The handler function registered above
function updateAuthInfo(e) {
  if (e.data.error !== undefined) {
    console.log('Error - ' + e.data.error)
  } else {
    console.log('Authorization completed')
  }

  // 4. Closing the modal window
  popup.close();
}

The code below will be sent to the modal window from your backend server when the user gets to Redirect URl

<!doctype html>
<html lang="en">
<head>
  <title>OAuth Postback</title>
  <script>
    //Passing data to the main window, the data set is defined by you
    if(window.opener){
      window.opener.postMessage({'error': undefined, 'status': 'ok'}, "*");
    }
  </script>
</head>
</html>

After processing the code above, the main window will indicate the result.

We recommend closing the modal window automatically, as is done in the example, so that users don’t get confused in windows.

3. Exchange of the authorization code to access token and refresh token

After getting the authorization code, you need to make a request to a special POST method /oauth2/access_token, as explained below. As a response, you’ll get a pair of access and refresh tokens and the time in seconds until the tokens will expire.

The access token is similar to the session key. It can be saved in the integration and used for API requests until its lifetime expires. The token must be accessible only to your integration, that’s why we recommend not saving it in browser cookies, or open configuration files, etc.

URL of the Method

POST /oauth2/access_token

Example of cURL request template

curl https://subdomain.kommo.com/oauth2/access_token -d \
'{"client_id":"xxx-xxx-xxx-xxx-xxx","client_secret":"xxxxxx","grant_type":"authorization_code","code":"xxxxxxxx",
"redirect_uri":"https://test.test/"}' \
-H 'Content-Type:application/json' \
-X POST

Request body

{
  "client_id": "xxxx",
  "client_secret": "xxxx",
  "grant_type": "authorization_code",
  "code": "xxxxxxx",
  "redirect_uri": "https://test.test"
}

Request Body parameters

Parameter Description
client_id Integration ID
client_secret Secret key
grant_type Type of authorization data (for Authorization code: authorization_code)
code The received authorization code
redirect_uri Redirect URI indicated in the integration settings

Response

{
  "token_type": "Bearer",
  "expires_in": 86400,
  "access_token": "xxxxxx",
  "refresh_token": "xxxxx"
}

Parameters of the response

Parameter Description
token_type Token type (Bearer)
expires_in Time in seconds, which shows when the token will expire
access_token Access token
refresh_token Refresh token

HTTP response codes

Code Situation
200 Request successfully processed
400 Incorrect data was transmitted. Details are available in the response body

Getting an access token with Authorization code via PHP

<?php
$subdomain = 'test'; ///subdomain of the account 
$link = 'https://' . $subdomain . '.kommo.com/oauth2/access_token'; //Creating URL for request

/** Gathering data for request */
$data = [
	'client_id' => 'xxxx',
	'client_secret' => 'xxxx',
	'grant_type' => 'authorization_code',
	'code' => 'xxxxxx',
	'redirect_uri' => 'https://test.com/',
];

/**
 * We need to initiate a request to the server.
 * Let’s use library with cURL.
 * You can also use cross-platform cURL, if you don’t code on PHP.
 */
$curl = curl_init(); //Saving descriptor cURL
/** Installing required options for session cURL  */
curl_setopt($curl,CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl,CURLOPT_USERAGENT,'amo-oAuth-client/1.0');
curl_setopt($curl,CURLOPT_URL, $link);
curl_setopt($curl,CURLOPT_HTTPHEADER,['Content-Type:application/json']);
curl_setopt($curl,CURLOPT_HEADER, false);
curl_setopt($curl,CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($curl,CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($curl,CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($curl,CURLOPT_SSL_VERIFYHOST, 2);
$out = curl_exec($curl); //Initiating request to API and saving response to variable
$code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl); 
/** 
* Now we can process responses from the server. 
* It’s an example, you can process this data the way you want. 
*/ 
$code = (int)$code;
$errors = [
	400 => 'Bad request',
	401 => 'Unauthorized',
	403 => 'Forbidden',
	404 => 'Not found',
	500 => 'Internal server error',
	502 => 'Bad gateway',
	503 => 'Service unavailable',
];

try
{
	/** If the response code is not successful - return an error message  */
	if ($code < 200 || $code > 204) {
		throw new Exception(isset($errors[$code]) ? $errors[$code] : 'Undefined error', $code);
	}
}
catch(\Exception $e)
{
	die('Error: ' . $e->getMessage() . PHP_EOL . 'Error code: ' . $e->getCode());
}

/**
 * Data will be received in JSON, that’s why to get readable data,
 * we need to parse that data that PHP will understand
 */
$response = json_decode($out, true);

$access_token = $response['access_token']; //Access token
$refresh_token = $response['refresh_token']; //Refresh token
$token_type = $response['token_type']; //Token type
$expires_in = $response['expires_in']; //After how long does the token expire

4. Getting a new access token once it expires

From the previous section you may have noticed that with an Access token we get a Refresh token. It is required to continue working with API, after the expiration of the access token. It’s a common action.

Refresh token has two duration limitations:

  1. The refresh token lifespan is 3 months. If an integration is not used in 3 months, no request was made to actualize the key, then the integration will lose access to data and it’s required to ask for permission from the user again.
  2. Once the refresh token is changed and the new one is used to get a new pair of access & refresh tokens, the old refresh token becomes outdated (irrelevant). After getting the new refresh token you need to save it, otherwise, you’ll need to re-request access from the user.

After the expiration date, the possibility of getting an access token from the refresh token becomes impossible. To exchange it, you need to make a request to a special method with a valid refresh token. In response, you will get new access and refresh tokens.

Method URL

POST /oauth2/access_token

Example of cURL request template

curl https://subdomain.kommo.com/oauth2/access_token -d \
'{"client_id":"xxx-xxx-xxx-xxx-xxx",
  "client_secret":"xxxxxx",grant_type":"refresh_token","refresh_token":"xxxxxxxx",
  "redirect_uri":"https://test.test/"}' \
-H 'Content-Type:application/json' \
-X POST

Example of a request body JSON

{
 "client_id": "xxxx",
  "client_secret": "xxxx",
  "grant_type": "refresh_token",
  "refresh_token": "xxxxx",
  "redirect_uri": "https://test.test"
}

Request Parameters body description

Parameter Data type Description
client_id string Integration ID
client_secret string Integration secret ID
grant_type string Type of authorization data (for refresh token: refresh_token)
refresh_token string Refresh token
redirect_uri string Redirect URI indicated in integration settings

Data type header on successful result

Content-Type: application/json

Error data type header

Content-Type: application/json

HTTP response codes

Code Condition
200 Request successfully processed
400 Incorrect data was transmitted. Details are available in the response body

Example of a response

{
  "token_type": "Bearer",
  "expires_in": 86400,
  "access_token": "xxxxxx",
  "refresh_token": "xxxxx"
}

Response parameters description

Parameter Description
token_type Type of token (Bearer)
expires_in Time in seconds, which shows after how long the token will expire
access_token Access token
refresh_token Refresh token

Getting an Access token with Refresh token via PHP

<?php
$subdomain = 'test'; //Subdomain of the account
$link = 'https://' . $subdomain . '.kommo.com/oauth2/access_token'; //Creating URL for request

/** Gathering data for request */
$data = [
	'client_id' => 'xxxx',
	'client_secret' => 'xxxx',
	'grant_type' => 'refresh_token',
    'refresh_token' => 'xxxxxx',
	'redirect_uri' => 'https://test.com/',
];

/**
 * We need to initiate the request to the server.
 * Let’s use the library with cURL.
 * You can also use cross-platform cURL if you don’t code on PHP.
 */
$curl = curl_init(); //Saving descriptor cURL
/** Installing required options for session cURL */
curl_setopt($curl,CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl,CURLOPT_USERAGENT,'Kommo-oAuth-client/1.0');
curl_setopt($curl,CURLOPT_URL, $link);
curl_setopt($curl,CURLOPT_HTTPHEADER,['Content-Type:application/json']);
curl_setopt($curl,CURLOPT_HEADER, false);
curl_setopt($curl,CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($curl,CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($curl,CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($curl,CURLOPT_SSL_VERIFYHOST, 2);
$out = curl_exec($curl); //Initiating request to API and saving response to variable
$code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
/** 
* Now we can process responses from the server. 
* It’s an example, you can process this data the way you want. 
*/ 
$code = (int)$code; 
$errors = [ 
            400 => 'Bad request', 
            401 => 'Unauthorized', 
            403 => 'Forbidden', 
            404 => 'Not found', 
            500 => 'Internal server error', 
            502 => 'Bad gateway', 
            503 => 'Service unavailable', 
          ]; 
try { /** If code of the response is not successful - return message of error */ 
      if ($code < 200 || $code > 204) 
       { throw new Exception(isset($errors[$code]) ? $errors[$code] : 'Undefined error', $code); } 
} 
catch(\Exception $e) { die('Error: ' . $e->getMessage() . PHP_EOL . 'Error code: ' . $e->getCode()); } 
/** 
* Data will be received in JSON, that’s why to get readable data, 
* we need to parse data that PHP will understand 
*/ 
$response = json_decode($out, true);
 
$access_token = $response['access_token']; //Access token 
$refresh_token = $response['refresh_token']; //Refresh token 
$token_type = $response['token_type']; //Type of token 
$expires_in = $response['expires_in']; //After how long does the token expire 

Important note: when sending the refresh token, you get a new pair of tokens: access and refresh, but the old refresh token will still be functional and you can use it until you use the new received keys.

Let’s consider the following scenario:

  1. When the lifetime of the access token ends, the integration sends the refresh token to get a new access token, and as usual Kommo returns a new refresh token with it.
  2. A network error happens and the integration didn’t get the new access and refresh tokens.
  3. The integration in this case should send the old refresh token, which is still valid, to get new access and refresh tokens.

5. Requests to API by exchanging an access token

With the help of the received access token, you can easily make requests to API Kommo. For that you’ll need to make little changes to the requests that are currently sent to API.

You don’t need to send cookies with each request, and you don’t need to authorize with parameters USER_LOGIN and USER_HASH. Instead of that, you need to add header Authorization: Bearer {access token}

Example of a request to method account

<?php
$subdomain = 'test'; //Subdomain of the account
$link = 'https://' . $subdomain . '.kommo.com/api/v4/account'; //Creation of URL for request
/** Getting access_token from your storage */
$access_token = 'xxxx';
/** Creating headers */
$headers = [
	'Authorization: Bearer ' . $access_token
];
/**
 * We need to initiate a request to the server.
 * Let’s use library with cURL
 * You can also use cross platform cURL, if you don’t code on PHP.
 */
$curl = curl_init(); //Saving descriptor of cURL
/** Installing required options for session cURL  */
curl_setopt($curl,CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl,CURLOPT_USERAGENT,'Kommo-oAuth-client/1.0');
curl_setopt($curl,CURLOPT_URL, $link);
curl_setopt($curl,CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl,CURLOPT_HEADER, false);
curl_setopt($curl,CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($curl,CURLOPT_SSL_VERIFYHOST, 2);
$out = curl_exec($curl); //Initiating request to API and saving response to variable
$code = curl_getinfo($curl, CURLINFO_HTTP_CODE);
curl_close($curl);
/** Now we can process the response received from the server.
 *  It’s an example, you can process this data the way you want. */
$code = (int)$code;
$errors = [
	400 => 'Bad request',
	401 => 'Unauthorized',
	403 => 'Forbidden',
	404 => 'Not found',
	500 => 'Internal server error',
	502 => 'Bad gateway',
	503 => 'Service unavailable',
];

try
{
	/** If the response code is not successful - return message of error  */
	if ($code < 200 && $code > 204) {
		throw new Exception(isset($errors[$code]) ? $errors[$code] : 'Undefined error', $code);
	}
}
catch(\Exception $e)
{
	die('Error: ' . $e->getMessage() . PHP_EOL . 'Error code: ' . $e->getCode());
}

Like this, you can make requests to all methods of API, for which a token has enough permissions. The token has the rights of the user who granted access.

6. Hook to disable integration

Starting from November 2021, you can specify the address to which the request will be sent when the integration is disabled.
After receiving the hook, you will be able to stop the integration, limit requests to the account in which the disconnection occurred.
We recommend specifying this link, as it will help you to avoid making unnecessary API requests, track when integration was disabled.

7. Error handling

When working with the logic above, some exceptions that need to be handled may appear. Let’s take a look at all of them:

  1. If the user has not given permission to access the account, in case you used the Kommo button, the function that is passed in one of the parameters will be called. You can read more in the Button on the site article. Otherwise, if the page was opened without a button, in case of decline, a redirect will happen to the Redirect URI with the GET-parameter error=access_denied.
  2. If the administrator of the account deactivated the installation of the integration, then the access token given to it will be revoked. When requesting API you will get HTTP code 401. To continue the work of the integration, the integrator must again obtain authorization for their integration from the user.
  3. If you didn’t save the actual refresh token, or it was lost or more than 3 months have passed, to continue the work of the integration, you need to go through the app authorization process once again.
  4. If you lost the main keys of an integration, or you published them accidentally, then you can refresh the secret key in the integration modal window of the account, where it was created. After refreshing the secret key of the integration, you need to refresh the secret key in the configurations of your integration.
  5. If a network error happened during the receiving of the new access and refresh tokens, the old refresh token would still work normally. The integration in this case should send the old refresh token, which is still valid, to get new access and refresh tokens.