S2S ping: Difference between revisions
 (Created page with "= Общий алгоритм работы = # Пользователь приходит на ваш сайт. Вы генерируете уникальный <code>kmnrId</code> и отстукиваетесь с ним на сервер Kaminari на URL /ping, мы сохраняем данные в кэш. # Затем вы показываете пользователю страницу с нашим JS-скриптом, добавив в вызов скрипта...")  | 
				No edit summary  | 
				||
| (26 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
=   | <languages/>  | ||
#   | <translate>  | ||
#   | <!--T:1-->  | ||
#   | = General workflow =  | ||
#   | # The user arrives at your website. You generate a unique <code>kmnrId</code> and send it to Kaminari server via /ping URL, and we save the data in the cache.  | ||
##   | # Then you show the user a page with our JavaScript script, adding the same <code>kmnrId</code> to the script call.  | ||
##   | # We collect user data and send it to the server.  | ||
##   | # On the server, we check in the cache:  | ||
## If there is a record with a similar <code>kmnrId</code> (coming from /ping), we combine the data from the cache with the results of the check and write them to the statistics.  | |||
## If there is no record with such an <code>kmnrId</code>, we wait up to five minutes. If the second record still does not arrive, we write what we have in the statistics.  | |||
## We also periodically check the cache and look for expired clicks that came to /ping but remained unpaired. If we couldn't verify them in any way, we write them to statistics with the status "Technical Losses."  | |||
=   | = Client-side configuration = <!--T:2-->  | ||
==   | <!--T:3-->  | ||
== Sending data to https://kaminari.systems/v2/ping ==  | |||
When a user visits the page, it is necessary to generate a unique display <code>kmnrId</code> on the client-side backend.  | |||
<!--T:4-->  | |||
Then, using PHP, Python, NodeJS, depending on the technology your website is built on, send initializing information to the https://kaminari.systems/v2/ping in the background.  | |||
<!--T:5-->  | |||
The request may not be accepted on the first attempt (in which case, the server will respond with a 204 status),  so we recommend sending the request in a loop until you receive a response with a 200 status.  | |||
<!--T:6-->  | |||
The data should be sent using the POST method in JSON format.  | |||
<!--T:7-->  | |||
List of parameters:  | |||
<!--T:8-->  | |||
{| class="wikitable"  | {| class="wikitable"  | ||
|-  | |-  | ||
!   | ! Parameter Name !! Parameter Description !! Mandatory?  | ||
|-  | |||
| kmnrId || Random impression identifier. Generated on the client side. It can be anything - UUID, random number, random string of text. '''Must be sent as a string.''' || yes  | |||
|-  | |||
| kmnrKey || Integration identifier within which the impression is analyzed. || yes  | |||
|-  | |||
| sub1 || Filled sub-tags. If you do not use certain tags, there is no need to send them. || no  | |||
|-  | |||
| sub2 || ... || no  | |||
|-  | |-  | ||
|   | | sub3 || ... || no  | ||
|-  | |-  | ||
|   | | sub4 || ... || no  | ||
|-  | |||
| sub5 || ... || no  | |||
|-  | |||
| sub6 || ... || no  | |||
|-  | |||
| sub7 || ... || no  | |||
|}  | |||
<!--T:9-->  | |||
In addition, the following headers obtained from the user should be added to this request:  | |||
{| class="wikitable"  | |||
|-  | |-  | ||
! Parameter Name !! Parameter Description !! Mandatory?  | |||
|-  | |-  | ||
|   | | user-agent || User agent || yes  | ||
|-  | |-  | ||
|   | | referer || Page the user came from || no  | ||
|-  | |-  | ||
|   | | accept-language || Browser interface language || yes  | ||
|-  | |-  | ||
|   | | x-original-ip || Real user IP || yes  | ||
|-  | |-  | ||
|   | | x-forwarded-for || IP || yes  | ||
|-  | |-  | ||
|   | | x-real-ip || IP || no  | ||
|-  | |-  | ||
|   | | sec-ch-ua-arch || || no  | ||
|-  | |-  | ||
|   | | sec-ch-ua || || no  | ||
|-  | |-  | ||
|   | | sec-ch-ua-full-version || || no  | ||
|-  | |-  | ||
| device-memory || || no  | |||
|-  | |-  | ||
|   | | dpr || || no  | ||
|-  | |-  | ||
|   | | sec-ch-ua-mobile || || no  | ||
|-  | |-  | ||
|   | | sec-ch-ua-model || || no  | ||
|-  | |-  | ||
|   | | sec-ch-ua-platform || || no  | ||
|-  | |-  | ||
|   | | sec-ch-ua-platform-version || || no  | ||
|-  | |-  | ||
|   | | viewport-width || || no  | ||
|}  | |}  | ||
<!--T:10-->  | |||
Example in CURL:  | |||
<pre>  | <pre>  | ||
curl 'https://kaminari.systems/v2/ping' \  | curl 'https://kaminari.systems/v2/ping' \  | ||
   -H 'accept: application/json' \    |    -H 'accept: application/json' \  | ||
   -H 'accept-language: en-US,en;q=0.9' \    |    -H 'accept-language: en-US,en;q=0.9,uk;q=0.8' \  | ||
   -H 'cache-control: no-cache' \    |    -H 'cache-control: no-cache' \  | ||
   -H 'content-type:   |    -H 'content-type: application/json;charset=UTF-8' \  | ||
   -H 'origin: https://test.com' \    |    -H 'origin: https://test.com' \  | ||
   -H 'pragma: no-cache' \    |    -H 'pragma: no-cache' \  | ||
   -H 'referer: https://test.com/' \    |    -H 'referer: https://test.com/' \  | ||
   -H 'user-agent: Mozilla/5.0 (  |    -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36' \  | ||
   --data-raw '{"kmnrKey":"  |   -H 'x-original-ip: 127.0.0.1' \  | ||
  -H 'x-forwarded-for: 192.168.0.1' \  | |||
  -H 'sec-ch-ua-arch: "x86"' \  | |||
  -H 'sec-ch-ua: "Google Chrome";v="129", "Not=A?Brand";v="8", "Chromium";v="129"' \  | |||
  -H 'sec-ch-ua-full-version: "129.0.6668.100"' \  | |||
  -H 'device-memory: 8' \  | |||
  -H 'dpr: 2' \  | |||
  -H 'sec-ch-ua-mobile: ?0' \  | |||
  -H 'sec-ch-ua-model: ""' \  | |||
  -H 'sec-ch-ua-platform: "macOS"' \  | |||
  -H 'sec-ch-ua-platform-version: "14.5.0"' \  | |||
  -H 'viewport-width: 981' \  | |||
   --data-raw '{"kmnrKey":"XXXXXXXX","kmnrId":"1125570260","sub1":"test","sub2":"1001","sub3":"10","sub4":"1385282124113622","sub5":"222","sub6":"555666","sub7":"8833705265931305"}'    | |||
   --compressed  |    --compressed  | ||
</pre>  | </pre>  | ||
==   | <!--T:11-->  | ||
Example in PHP:  | |||
<pre>  | |||
$url = 'https://kaminari.systems/v2/ping';  | |||
$ch = curl_init( $url );  | |||
$payload = json_encode([  | |||
    'kmnrKey' => 'XXXXXXXX',  | |||
    'kmnrId' => '1125570260',  | |||
    'sub1' => 'test',  | |||
    'sub2' => '1001',  | |||
    'sub3' => '10',  | |||
    'sub4' => '1385282124113622',  | |||
    'sub5' => '222',  | |||
    'sub6' => '555666',  | |||
    'sub7' => '8833705265931305',  | |||
]);  | |||
<!--T:12-->  | |||
curl_setopt( $ch, CURLOPT_POSTFIELDS, $payload );  | |||
curl_setopt( $ch, CURLOPT_HTTPHEADER, [  | |||
    'Content-Type:application/json;charset=UTF-8',  | |||
    'Accept-Language:' . $_SERVER['HTTP_ACCEPT_LANGUAGE'],  | |||
    'User-Agent:' . $_SERVER['HTTP_USER_AGENT'],  | |||
    isset($_SERVER['HTTP_REFERER']) ? 'Referer:' . $_SERVER['HTTP_REFERER'] : '',  | |||
    'X-Original-Ip:' . $_SERVER['REMOTE_ADDR'],  | |||
    isset($_SERVER['X_FORWARDED_FOR']) ? 'X-Forwarded-For:' . $_SERVER['X_FORWARDED_FOR'] : '',  | |||
    isset($_SERVER['HTTP_SEC_CH_UA_ARCH']) ? 'Sec-CH-UA-Arch:' . $_SERVER['HTTP_SEC_CH_UA_ARCH'] : '',  | |||
    isset($_SERVER['HTTP_SEC_CH_UA']) ? 'Sec-CH-UA:' . $_SERVER['HTTP_SEC_CH_UA'] : '',  | |||
    isset($_SERVER['HTTP_SEC_CH_UA_FULL_VERSION']) ? 'Sec-CH-UA-Full-Version:' . $_SERVER['HTTP_SEC_CH_UA_FULL_VERSION'] : '',  | |||
    isset($_SERVER['HTTP_DEVICE_MEMORY']) ? 'Device-Memory:' . $_SERVER['HTTP_DEVICE_MEMORY'] : '',  | |||
    isset($_SERVER['HTTP_DPR']) ? 'DPR:' . $_SERVER['HTTP_DPR'] : '',  | |||
    isset($_SERVER['HTTP_SEC_CH_UA_MOBILE']) ? 'Sec-CH-UA-Mobile:' . $_SERVER['HTTP_SEC_CH_UA_MOBILE'] : '',  | |||
    isset($_SERVER['HTTP_SEC_CH_UA_MODEL']) ? 'Sec-CH-UA-Model:' . $_SERVER['HTTP_SEC_CH_UA_MODEL'] : '',  | |||
    isset($_SERVER['HTTP_SEC_CH_UA_PLATFORM']) ? 'Sec-CH-UA-Platform:' . $_SERVER['HTTP_SEC_CH_UA_PLATFORM'] : '',  | |||
    isset($_SERVER['HTTP_SEC_CH_UA_PLATFORM_VERSION']) ? 'Sec-CH-UA-Platform-Version:' . $_SERVER['HTTP_SEC_CH_UA_PLATFORM_VERSION'] : '',  | |||
    isset($_SERVER['HTTP_VIEWPORT_WIDTH']) ? 'Viewport-Width:' . $_SERVER['HTTP_VIEWPORT_WIDTH'] : '',  | |||
]);  | |||
curl_exec($ch);  | |||
curl_close($ch);  | |||
</pre>  | |||
<!--T:13-->  | |||
== Adding kmnrId to the script ==  | |||
The generated <code>kmnrId</code>, as well as the <code>kmnrKey</code> and sub-tags, should then be passed into the call of the JavaScript script on the page.  | |||
<!--T:14-->  | |||
<pre>  | <pre>  | ||
<script>  | <script>  | ||
     window.kmnr = {  |      window.kmnr = {  | ||
         kmnrKey: '  |          kmnrKey: 'XXXXXXXX',  | ||
         kmnrId: '1125570260',  |          kmnrId: '1125570260',  | ||
         sub1: '  |          sub1: 'test',  | ||
         sub2: '  |          sub2: '1001',  | ||
        sub3: '10',  | |||
        sub4: '1385282124113622',  | |||
        sub5: '222',  | |||
        sub6: '555666',  | |||
        sub7: '8833705265931305',  | |||
     };  |      };  | ||
     var kmnrSc = document.createElement('script');  |      <!--T:15-->  | ||
var kmnrSc = document.createElement('script');  | |||
     var kmnrPrnt = document.getElementsByTagName('head')[0] || document.body;  |      var kmnrPrnt = document.getElementsByTagName('head')[0] || document.body;  | ||
     kmnrSc.setAttribute('async', true);  |      kmnrSc.setAttribute('async', true);  | ||
| Line 99: | Line 189: | ||
</script>  | </script>  | ||
</pre>  | </pre>  | ||
= Testing = <!--T:16-->  | |||
<!--T:17-->  | |||
For testing data transmission and ensuring their compatibility with the API, you can use the following URL: https://kaminari.systems/v1/pingtest  | |||
<!--T:18-->  | |||
=== Example in PHP: ===  | |||
<pre>  | |||
$url = 'https://kaminari.systems/v1/pingtest';  | |||
try {  | |||
    $ch = curl_init( $url );  | |||
    $payload = json_encode([  | |||
        'kmnrKey' => 'XXXXXXXX',  | |||
        'kmnrId' => (string)mt_rand(),  | |||
        'sub1' => 'test',  | |||
        'sub2' => '1001',  | |||
        'sub3' => '10',  | |||
        'sub4' => '40',  | |||
        'sub5' => '555',  | |||
        'sub6' => '6',  | |||
        'sub7' => '77777',  | |||
    ]);  | |||
    <!--T:19-->  | |||
curl_setopt( $ch, CURLOPT_POSTFIELDS, $payload );  | |||
    curl_setopt( $ch, CURLOPT_HTTPHEADER, [  | |||
        'Content-Type:application/json',  | |||
        'Accept-Language:' . $_SERVER['HTTP_ACCEPT_LANGUAGE'],  | |||
        'User-Agent:' . $_SERVER['HTTP_USER_AGENT'],  | |||
        'DPR:2',  | |||
        isset($_SERVER['HTTP_REFERER']) ? 'Referer:' . $_SERVER['HTTP_REFERER'] : 'Referer:""',  | |||
    ]);  | |||
    curl_setopt( $ch, CURLOPT_HEADER, true);  | |||
    curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );  | |||
    $response = curl_exec($ch);  | |||
    $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);  | |||
    $header = substr($response, 0, $header_size);  | |||
    $body = substr($response, $header_size);  | |||
    $body = str_replace('", "', '",<br />    "', $body);  | |||
    $body = str_replace('{ "', '{<br />    "', $body);  | |||
    echo "<pre>1. Response length: $header_size</pre>";  | |||
    echo "<pre>2. Response body: $body</pre>";  | |||
    <!--T:20-->  | |||
'curl error: ' . curl_error($ch);  | |||
    curl_close($ch);  | |||
} catch (Exception $e) {  | |||
    echo "Error register User: {$e->getMessage()}";  | |||
}  | |||
</pre>  | |||
<!--T:21-->  | |||
Response :  | |||
<pre>  | |||
1. Response length: 287  | |||
2. Response body: {"errors": {  | |||
    "X-Forwarded-For":"recommended to add in request headers",  | |||
    "X-Real-IP":"recommended to add in request headers",  | |||
    "sec-ch-ua-arch":"recommended to add in request headers",  | |||
    "sec-ch-ua":"recommended to add in request headers",  | |||
    "sec-ch-ua-full-version":"recommended to add in request headers",  | |||
    "device-memory":"recommended to add in request headers",  | |||
    "sec-ch-ua-mobile":"recommended to add in request headers",  | |||
    "sec-ch-ua-model":"recommended to add in request headers",  | |||
    "sec-ch-ua-platform":"recommended to add in request headers",  | |||
    "sec-ch-ua-platform-version":"recommended to add in request headers",  | |||
    "viewport-width":"recommended to add in request headers"}}  | |||
</pre>  | |||
<!--T:22-->  | |||
=== Example in Node.js: ===  | |||
<pre>  | |||
const https = require('https');  | |||
<!--T:23-->  | |||
const payload = JSON.stringify({  | |||
    'kmnrKey': 'XXXXXXXX',  | |||
    'kmnrId': (Math.random() + 1).toString(36).substring(9),  | |||
    'sub1': 'test',  | |||
    'sub2': '1001',  | |||
    'sub3': '10',  | |||
    'sub4': '40',  | |||
    'sub5': '555',  | |||
    'sub6': '6',  | |||
    'sub7': '77777',  | |||
});  | |||
<!--T:24-->  | |||
const options = {  | |||
    host: 'kaminari.click',  | |||
    port: 443,  | |||
    path: '/v1/pingtest',  | |||
    method: 'POST',  | |||
    headers: {   | |||
        'Content-Type': 'application/json',  | |||
        'Content-Length': Buffer.byteLength(payload),  | |||
        'Accept-Language': 'en-US,en;q=0.5',  | |||
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0',  | |||
        'DPR': '2',  | |||
        'Referer': '""',  | |||
    }  | |||
};  | |||
<!--T:25-->  | |||
const req = https  | |||
    .request(options, (res) => {  | |||
        let data = '';  | |||
        <!--T:26-->  | |||
res.on('data', (chunk) => {  | |||
            data += chunk;  | |||
        });  | |||
        res.on('end', () => {  | |||
            try {  | |||
                data = JSON.parse(data);  | |||
                console.log(data);  | |||
            } catch {  | |||
                console.log(data);  | |||
            }  | |||
        });  | |||
    });  | |||
<!--T:27-->  | |||
req.on('error', (err) => {  | |||
    console.log("Error: " + err.message);  | |||
});  | |||
req.write(payload);  | |||
req.end();  | |||
</pre>  | |||
<!--T:28-->  | |||
Response:  | |||
<pre>  | |||
{  | |||
  errors: {  | |||
    'X-Forwarded-For': 'recommended to add in request headers',  | |||
    'X-Real-IP': 'recommended to add in request headers',  | |||
    'sec-ch-ua-arch': 'recommended to add in request headers',  | |||
    'sec-ch-ua': 'recommended to add in request headers',  | |||
    'sec-ch-ua-full-version': 'recommended to add in request headers',  | |||
    'device-memory': 'recommended to add in request headers',  | |||
    'sec-ch-ua-mobile': 'recommended to add in request headers',  | |||
    'sec-ch-ua-model': 'recommended to add in request headers',  | |||
    'sec-ch-ua-platform': 'recommended to add in request headers',  | |||
    'sec-ch-ua-platform-version': 'recommended to add in request headers',  | |||
    'viewport-width': 'recommended to add in request headers'  | |||
  }  | |||
}  | |||
</pre>  | |||
[[Category:Features]]  | |||
</translate>  | |||
Latest revision as of 16:53, 11 October 2024
General workflow
- The user arrives at your website. You generate a unique 
kmnrIdand send it to Kaminari server via /ping URL, and we save the data in the cache. - Then you show the user a page with our JavaScript script, adding the same 
kmnrIdto the script call. - We collect user data and send it to the server.
 - On the server, we check in the cache:
- If there is a record with a similar 
kmnrId(coming from /ping), we combine the data from the cache with the results of the check and write them to the statistics. - If there is no record with such an 
kmnrId, we wait up to five minutes. If the second record still does not arrive, we write what we have in the statistics. - We also periodically check the cache and look for expired clicks that came to /ping but remained unpaired. If we couldn't verify them in any way, we write them to statistics with the status "Technical Losses."
 
 - If there is a record with a similar 
 
Client-side configuration
Sending data to https://kaminari.systems/v2/ping
When a user visits the page, it is necessary to generate a unique display kmnrId on the client-side backend.
Then, using PHP, Python, NodeJS, depending on the technology your website is built on, send initializing information to the https://kaminari.systems/v2/ping in the background.
The request may not be accepted on the first attempt (in which case, the server will respond with a 204 status), so we recommend sending the request in a loop until you receive a response with a 200 status.
The data should be sent using the POST method in JSON format.
List of parameters:
| Parameter Name | Parameter Description | Mandatory? | 
|---|---|---|
| kmnrId | Random impression identifier. Generated on the client side. It can be anything - UUID, random number, random string of text. Must be sent as a string. | yes | 
| kmnrKey | Integration identifier within which the impression is analyzed. | yes | 
| sub1 | Filled sub-tags. If you do not use certain tags, there is no need to send them. | no | 
| sub2 | ... | no | 
| sub3 | ... | no | 
| sub4 | ... | no | 
| sub5 | ... | no | 
| sub6 | ... | no | 
| sub7 | ... | no | 
In addition, the following headers obtained from the user should be added to this request:
| Parameter Name | Parameter Description | Mandatory? | 
|---|---|---|
| user-agent | User agent | yes | 
| referer | Page the user came from | no | 
| accept-language | Browser interface language | yes | 
| x-original-ip | Real user IP | yes | 
| x-forwarded-for | IP | yes | 
| x-real-ip | IP | no | 
| sec-ch-ua-arch | no | |
| sec-ch-ua | no | |
| sec-ch-ua-full-version | no | |
| device-memory | no | |
| dpr | no | |
| sec-ch-ua-mobile | no | |
| sec-ch-ua-model | no | |
| sec-ch-ua-platform | no | |
| sec-ch-ua-platform-version | no | |
| viewport-width | no | 
Example in CURL:
curl 'https://kaminari.systems/v2/ping' \
  -H 'accept: application/json' \
  -H 'accept-language: en-US,en;q=0.9,uk;q=0.8' \
  -H 'cache-control: no-cache' \
  -H 'content-type: application/json;charset=UTF-8' \
  -H 'origin: https://test.com' \
  -H 'pragma: no-cache' \
  -H 'referer: https://test.com/' \
  -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36' \
  -H 'x-original-ip: 127.0.0.1' \
  -H 'x-forwarded-for: 192.168.0.1' \
  -H 'sec-ch-ua-arch: "x86"' \
  -H 'sec-ch-ua: "Google Chrome";v="129", "Not=A?Brand";v="8", "Chromium";v="129"' \
  -H 'sec-ch-ua-full-version: "129.0.6668.100"' \
  -H 'device-memory: 8' \
  -H 'dpr: 2' \
  -H 'sec-ch-ua-mobile: ?0' \
  -H 'sec-ch-ua-model: ""' \
  -H 'sec-ch-ua-platform: "macOS"' \
  -H 'sec-ch-ua-platform-version: "14.5.0"' \
  -H 'viewport-width: 981' \
  --data-raw '{"kmnrKey":"XXXXXXXX","kmnrId":"1125570260","sub1":"test","sub2":"1001","sub3":"10","sub4":"1385282124113622","sub5":"222","sub6":"555666","sub7":"8833705265931305"}' 
  --compressed
Example in PHP:
$url = 'https://kaminari.systems/v2/ping';
$ch = curl_init( $url );
$payload = json_encode([
    'kmnrKey' => 'XXXXXXXX',
    'kmnrId' => '1125570260',
    'sub1' => 'test',
    'sub2' => '1001',
    'sub3' => '10',
    'sub4' => '1385282124113622',
    'sub5' => '222',
    'sub6' => '555666',
    'sub7' => '8833705265931305',
]);
curl_setopt( $ch, CURLOPT_POSTFIELDS, $payload );
curl_setopt( $ch, CURLOPT_HTTPHEADER, [
    'Content-Type:application/json;charset=UTF-8',
    'Accept-Language:' . $_SERVER['HTTP_ACCEPT_LANGUAGE'],
    'User-Agent:' . $_SERVER['HTTP_USER_AGENT'],
    isset($_SERVER['HTTP_REFERER']) ? 'Referer:' . $_SERVER['HTTP_REFERER'] : '',
    'X-Original-Ip:' . $_SERVER['REMOTE_ADDR'],
    isset($_SERVER['X_FORWARDED_FOR']) ? 'X-Forwarded-For:' . $_SERVER['X_FORWARDED_FOR'] : '',
    isset($_SERVER['HTTP_SEC_CH_UA_ARCH']) ? 'Sec-CH-UA-Arch:' . $_SERVER['HTTP_SEC_CH_UA_ARCH'] : '',
    isset($_SERVER['HTTP_SEC_CH_UA']) ? 'Sec-CH-UA:' . $_SERVER['HTTP_SEC_CH_UA'] : '',
    isset($_SERVER['HTTP_SEC_CH_UA_FULL_VERSION']) ? 'Sec-CH-UA-Full-Version:' . $_SERVER['HTTP_SEC_CH_UA_FULL_VERSION'] : '',
    isset($_SERVER['HTTP_DEVICE_MEMORY']) ? 'Device-Memory:' . $_SERVER['HTTP_DEVICE_MEMORY'] : '',
    isset($_SERVER['HTTP_DPR']) ? 'DPR:' . $_SERVER['HTTP_DPR'] : '',
    isset($_SERVER['HTTP_SEC_CH_UA_MOBILE']) ? 'Sec-CH-UA-Mobile:' . $_SERVER['HTTP_SEC_CH_UA_MOBILE'] : '',
    isset($_SERVER['HTTP_SEC_CH_UA_MODEL']) ? 'Sec-CH-UA-Model:' . $_SERVER['HTTP_SEC_CH_UA_MODEL'] : '',
    isset($_SERVER['HTTP_SEC_CH_UA_PLATFORM']) ? 'Sec-CH-UA-Platform:' . $_SERVER['HTTP_SEC_CH_UA_PLATFORM'] : '',
    isset($_SERVER['HTTP_SEC_CH_UA_PLATFORM_VERSION']) ? 'Sec-CH-UA-Platform-Version:' . $_SERVER['HTTP_SEC_CH_UA_PLATFORM_VERSION'] : '',
    isset($_SERVER['HTTP_VIEWPORT_WIDTH']) ? 'Viewport-Width:' . $_SERVER['HTTP_VIEWPORT_WIDTH'] : '',
]);
curl_exec($ch);
curl_close($ch);
Adding kmnrId to the script
The generated kmnrId, as well as the kmnrKey and sub-tags, should then be passed into the call of the JavaScript script on the page.
<script>
    window.kmnr = {
        kmnrKey: 'XXXXXXXX',
        kmnrId: '1125570260',
        sub1: 'test',
        sub2: '1001',
        sub3: '10',
        sub4: '1385282124113622',
        sub5: '222',
        sub6: '555666',
        sub7: '8833705265931305',
    };
    var kmnrSc = document.createElement('script');
    var kmnrPrnt = document.getElementsByTagName('head')[0] || document.body;
    kmnrSc.setAttribute('async', true);
    kmnrSc.setAttribute('charset', 'utf-8');
    kmnrSc.src = '//kaminari.systems/v1/script.js?kmnrKey=' + window.kmnr.kmnrKey;
    kmnrPrnt && kmnrPrnt.appendChild(kmnrSc);
</script>
Testing
For testing data transmission and ensuring their compatibility with the API, you can use the following URL: https://kaminari.systems/v1/pingtest
Example in PHP:
$url = 'https://kaminari.systems/v1/pingtest';
try {
    $ch = curl_init( $url );
    $payload = json_encode([
        'kmnrKey' => 'XXXXXXXX',
        'kmnrId' => (string)mt_rand(),
        'sub1' => 'test',
        'sub2' => '1001',
        'sub3' => '10',
        'sub4' => '40',
        'sub5' => '555',
        'sub6' => '6',
        'sub7' => '77777',
    ]);
    curl_setopt( $ch, CURLOPT_POSTFIELDS, $payload );
    curl_setopt( $ch, CURLOPT_HTTPHEADER, [
        'Content-Type:application/json',
        'Accept-Language:' . $_SERVER['HTTP_ACCEPT_LANGUAGE'],
        'User-Agent:' . $_SERVER['HTTP_USER_AGENT'],
        'DPR:2',
        isset($_SERVER['HTTP_REFERER']) ? 'Referer:' . $_SERVER['HTTP_REFERER'] : 'Referer:""',
    ]);
    curl_setopt( $ch, CURLOPT_HEADER, true);
    curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
    
    $response = curl_exec($ch);
    $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    $header = substr($response, 0, $header_size);
    $body = substr($response, $header_size);
    $body = str_replace('", "', '",<br />    "', $body);
    $body = str_replace('{ "', '{<br />    "', $body);
    echo "<pre>1. Response length: $header_size</pre>";
    echo "<pre>2. Response body: $body</pre>";
    'curl error: ' . curl_error($ch);
    curl_close($ch);
} catch (Exception $e) {
    echo "Error register User: {$e->getMessage()}";
}
Response :
1. Response length: 287
2. Response body: {"errors": {
    "X-Forwarded-For":"recommended to add in request headers",
    "X-Real-IP":"recommended to add in request headers",
    "sec-ch-ua-arch":"recommended to add in request headers",
    "sec-ch-ua":"recommended to add in request headers",
    "sec-ch-ua-full-version":"recommended to add in request headers",
    "device-memory":"recommended to add in request headers",
    "sec-ch-ua-mobile":"recommended to add in request headers",
    "sec-ch-ua-model":"recommended to add in request headers",
    "sec-ch-ua-platform":"recommended to add in request headers",
    "sec-ch-ua-platform-version":"recommended to add in request headers",
    "viewport-width":"recommended to add in request headers"}}
Example in Node.js:
const https = require('https');
const payload = JSON.stringify({
    'kmnrKey': 'XXXXXXXX',
    'kmnrId': (Math.random() + 1).toString(36).substring(9),
    'sub1': 'test',
    'sub2': '1001',
    'sub3': '10',
    'sub4': '40',
    'sub5': '555',
    'sub6': '6',
    'sub7': '77777',
});
const options = {
    host: 'kaminari.click',
    port: 443,
    path: '/v1/pingtest',
    method: 'POST',
    headers: { 
        'Content-Type': 'application/json',
        'Content-Length': Buffer.byteLength(payload),
        'Accept-Language': 'en-US,en;q=0.5',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0',
        'DPR': '2',
        'Referer': '""',
    }
};
const req = https
    .request(options, (res) => {
        let data = '';
        res.on('data', (chunk) => {
            data += chunk;
        });
        
        res.on('end', () => {
            try {
                data = JSON.parse(data);
                console.log(data);
            } catch {
                console.log(data);
            }
        });
    });
req.on('error', (err) => {
    console.log("Error: " + err.message);
});
req.write(payload);
req.end();
Response:
{
  errors: {
    'X-Forwarded-For': 'recommended to add in request headers',
    'X-Real-IP': 'recommended to add in request headers',
    'sec-ch-ua-arch': 'recommended to add in request headers',
    'sec-ch-ua': 'recommended to add in request headers',
    'sec-ch-ua-full-version': 'recommended to add in request headers',
    'device-memory': 'recommended to add in request headers',
    'sec-ch-ua-mobile': 'recommended to add in request headers',
    'sec-ch-ua-model': 'recommended to add in request headers',
    'sec-ch-ua-platform': 'recommended to add in request headers',
    'sec-ch-ua-platform-version': 'recommended to add in request headers',
    'viewport-width': 'recommended to add in request headers'
  }
}