📜 ⬆️ ⬇️

Setting up the Tinkoff Bank API. How is your intuition ....? Or a song about Oauth 2.0

A couple of weeks ago in one of the projects there was a question about the integration of CRM with the API of Bank Tinkoff. In particular, it was about getting a bank account statement.

The asset had:

  1. openapi.tinkoff.ru
  2. The telephone of the support service (taking into account the employment of the technical support department is the business of saving the drowning man, the handiwork of the drowning man himself).
  3. Loaded document: 24386_policy.pdf (with Russian letters inside, with amusing expressions, magic turns, of little use, but still a thing ...)

In the course of googlezh, reviews were also found that setting up the API of Tinkoff Bank is very interesting and non-trivial (see the article on banki.ru “API Tinkoff - we are too stupid for this” ).
')
Yes, I had to tinker a little, therefore, in order to save time for other shopmates, this article was written.

I note that the Tinkoff Bank API uses Oauth 2.0 for authorization.

Why do we need openapi.tinkoff.ru?

  1. for the test (see below);
  2. in order to guess what and how; there is no direct splint; working at the level of intuition! ...

Let's get started In the “SSO Authorization” section, click on “how / Hide” and then / secure / token # refresh-token (“Token issue via refresh token”), select grant_type as a parameter, then in the refresh_token field (you can get it in Personal user account). Click the button “Try it out!” The result of these actions is to get such an important thing as access_token (i.e., openapi.tinkoff.ru demonstrates the possibility of receiving it).

Next, we look at the section "Accounts and payments", click / partner / company / {INN} / excerpt ("Receive statement"). We study what parameters are necessary in order to get it: Authorization, INN, accountNumber, from, till.

Authorization - we guess that Authorization is nothing more than an access_token, which we received in the section “SSO Authorization”;
INN - the organization's TIN for which we set up the API;
from - from which day (discharge period);
till - on what day (discharge period).

Thus (we look at Oauth 2.0), the receipt of the statement data takes place in two stages - first we get access_token, then having access_token in our hands, we get the data of this very statement . Fine. The algorithm is clear, we write the code (the access parameters in the code are the values ​​for $ user, $ pass, $ refresh_token, $ inn, $ accountNumber — in the code below, they are changed, for obvious reasons).

Create the following files:

  1. The first configuration file is StartSettings.php
  2. The second file starting - Start.php
  3. The third file of posting / parsing data to / from the API is TinkoffInsertData.php ; use CURL (php).
  4. Empty database dump where you can fill in your statement data: bank.sql ; MySQL database (data is sent to the database via PDO).

So, look at the code and comments to it!

Settings file - StartSettings.php:

$host = '127.0.0.1'; $db = 'bank'; $user = 'root'; $pass = ''; $charset = 'utf8'; $dsn = "mysql:host=$host;dbname=$db;charset=$charset"; $opt = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, ]; $pdo = new PDO($dsn, $user, $pass, $opt); $user="IKu0jn98kllkI90kklii"; //20  $pass="ds4234SDFsdfsdijoijslkkdjfoIOi"; //30  $refresh_token='dsfh345kljlkjsdf098sdfkljklj098sdfkklKKLjhjihiKL90909llkrre5345dfFDDFretertERTERETfdgd==';// 88  $inn = '750151513135'; $accountNumber = '40802810300000121212';//20  $from_year = '1980'; $from_month = '01'; $from_day = '01'; $till_year = date('Y'); $till_month = date('m'); $till_day = date('d'); 

Startup file - Start.php:

 session_start(); error_reporting(E_ALL); include 'StartSettings.php'; include 'TinkoffInsertData.php'; TinkoffInsertData($user,$pass,$refresh_token, $inn, $accountNumber, $from_year, $from_month, $from_day, $till_year, $till_month, $till_day, $pdo); $stmt = $pdo->prepare("INSERT INTO `bank`.`dateofwork` (dateofwork) VALUES (NOW())"); $stmt->execute(); 

File posting / parsing data to / from the API - TinkoffInsertData.php:

 function TinkoffInsertData($user,$pass,$refresh_token, $inn, $accountNumber, $from_year, $from_month, $from_day, $till_year, $till_month, $till_day, $pdo){ //  -    access_token $from_date = $from_year."-".$from_month."-".$from_day.'%2B03%3A00%3A00'; $till_date = $till_year."-".$till_month."-".$till_day.'%2B03%3A00%3A00'; $params=['grant_type'=>'refresh_token', 'refresh_token'=>$refresh_token ]; $headers = [ 'POST /secure/token HTTP/1.1', 'Content-Type: application/x-www-form-urlencoded' ]; $curlURL='https://sso.tinkoff.ru/secure/token'; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL,$curlURL); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_USERPWD, $user . ":" . $pass); curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($params)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_VERBOSE, true); $curl_res = curl_exec($ch); if($curl_res) { $server_output = json_decode($curl_res); } // access_token -     2  $access_token_pos_start = strpos ($curl_res, 'access_token', 0); $access_token_pos_start = $access_token_pos_start + 15; $token_type_pos_start = strpos ($curl_res, "token_type", 0); $access_token = mb_substr($curl_res, $access_token_pos_start, ($token_type_pos_start-$access_token_pos_start-3)); //!....   ..... // ,    sleep,        //sleep(1); //  -     $params=[ 'Authorization'=>$access_token, 'INN'=>$inn, 'accountNumber'=>$accountNumber ]; $headers = [ 'Authorization: Bearer '.$access_token ]; $curlURL='https://sme-partner.tinkoff.ru/api/v1/partner/company/'.$inn.'/excerpt?accountNumber='.$accountNumber.'&from='.$from_date.'&till='.$till_date; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL,$curlURL); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_USERPWD, $user . ":" . $pass); curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_POST, false); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET'); curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($params)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_VERBOSE, true); $curl_res = curl_exec($ch); if($curl_res) { $server_output = json_decode($curl_res); } $IE_Edge_pos_start = strpos ($curl_res, 'IE=Edge', 0); $IE_Edge_pos_start = $IE_Edge_pos_start + 7; $tinkoff_json = mb_substr($curl_res, $IE_Edge_pos_start); $tinkoff_json = trim($tinkoff_json); $tinkoff_json = json_decode($tinkoff_json); //     ,  ;) foreach ($tinkoff_json as $k=>$v){ if($k=='accountNumber'){ if(!($v==$accountNumber)) die('not that accountNumber'); } } //$tinkoff_array -    json   foreach ($tinkoff_json as $k=>$v){ if($k=='operation'){ $i=0; foreach ($v as $t=>$s){ foreach ($s as $e=>$f){ $tinkoff_array[$i][$e]=$f; } $i++; } } } //   $tinkoff_array    for ($i=0;$i<count($tinkoff_array);$i++){ $temp_id = $pdo->query("SELECT count(*) FROM `justtin`.`tinkoff` WHERE id=".$tinkoff_array[$i]['id'].";")->fetchColumn(); if ($temp_id==0){ if (Get_highly_likely_is_number_bill($tinkoff_array[$i]['paymentPurpose'])!=""){ $stmt = $pdo->prepare("INSERT INTO `justtin`.`tinkoff` (id, date, amount, drawDate, payerName, payerInn, payerAccount, payerCorrAccount, payerBic, payerBank, chargeDate, recipient, recipientInn, recipientAccount, recipientCorrAccount, recipientBic, recipientBank, operationType, uin, paymentPurpose, creatorStatus, payerKpp, executionOrder, date_of_save) VALUES (:id, :date, :amount, :drawDate, :payerName, :payerInn, :payerAccount, :payerCorrAccount, :payerBic, :payerBank, :chargeDate, :recipient, :recipientInn, :recipientAccount, :recipientCorrAccount, :recipientBic, :recipientBank, :operationType, :uin, :paymentPurpose, :creatorStatus, :payerKpp, :executionOrder, NOW())"); $stmt->bindParam(':id', $tinkoff_array[$i]['id']); $stmt->bindParam(':date', $tinkoff_array[$i]['date']); $stmt->bindParam(':amount', $tinkoff_array[$i]['amount']); $stmt->bindParam(':drawDate', $tinkoff_array[$i]['drawDate']); $stmt->bindParam(':payerName', $tinkoff_array[$i]['payerName']); $stmt->bindParam(':payerInn', $tinkoff_array[$i]['payerInn']); $stmt->bindParam(':payerAccount', $tinkoff_array[$i]['payerAccount']); $stmt->bindParam(':payerCorrAccount', $tinkoff_array[$i]['payerCorrAccount']); $stmt->bindParam(':payerBic', $tinkoff_array[$i]['payerBic']); $stmt->bindParam(':payerBank', $tinkoff_array[$i]['payerBank']); $stmt->bindParam(':chargeDate', $tinkoff_array[$i]['chargeDate']); $stmt->bindParam(':recipient', $tinkoff_array[$i]['recipient']); $stmt->bindParam(':recipientInn', $tinkoff_array[$i]['recipientInn']); $stmt->bindParam(':recipientAccount', $tinkoff_array[$i]['recipientAccount']); $stmt->bindParam(':recipientCorrAccount', $tinkoff_array[$i]['recipientCorrAccount']); $stmt->bindParam(':recipientBic', $tinkoff_array[$i]['recipientBic']); $stmt->bindParam(':recipientBank', $tinkoff_array[$i]['recipientBank']); $stmt->bindParam(':operationType', $tinkoff_array[$i]['operationType']); $stmt->bindParam(':uin', $tinkoff_array[$i]['uin']); $stmt->bindParam(':paymentPurpose', $tinkoff_array[$i]['paymentPurpose']); $stmt->bindParam(':creatorStatus', $tinkoff_array[$i]['creatorStatus']); $stmt->bindParam(':payerKpp', $tinkoff_array[$i]['payerKpp']); $stmt->bindParam(':executionOrder', $tinkoff_array[$i]['executionOrder']); $stmt->execute(); } } } } "INSERT INTO` justtin`.`tinkoff` (id, date, amount, drawDate, payerName, payerInn, payerAccount, payerCorrAccount, payerBic, payerBank, chargeDate, recipient, recipientInn, recipientAccount, recipientCorrAccount, function TinkoffInsertData($user,$pass,$refresh_token, $inn, $accountNumber, $from_year, $from_month, $from_day, $till_year, $till_month, $till_day, $pdo){ //  -    access_token $from_date = $from_year."-".$from_month."-".$from_day.'%2B03%3A00%3A00'; $till_date = $till_year."-".$till_month."-".$till_day.'%2B03%3A00%3A00'; $params=['grant_type'=>'refresh_token', 'refresh_token'=>$refresh_token ]; $headers = [ 'POST /secure/token HTTP/1.1', 'Content-Type: application/x-www-form-urlencoded' ]; $curlURL='https://sso.tinkoff.ru/secure/token'; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL,$curlURL); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_USERPWD, $user . ":" . $pass); curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($params)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_VERBOSE, true); $curl_res = curl_exec($ch); if($curl_res) { $server_output = json_decode($curl_res); } // access_token -     2  $access_token_pos_start = strpos ($curl_res, 'access_token', 0); $access_token_pos_start = $access_token_pos_start + 15; $token_type_pos_start = strpos ($curl_res, "token_type", 0); $access_token = mb_substr($curl_res, $access_token_pos_start, ($token_type_pos_start-$access_token_pos_start-3)); //!....   ..... // ,    sleep,        //sleep(1); //  -     $params=[ 'Authorization'=>$access_token, 'INN'=>$inn, 'accountNumber'=>$accountNumber ]; $headers = [ 'Authorization: Bearer '.$access_token ]; $curlURL='https://sme-partner.tinkoff.ru/api/v1/partner/company/'.$inn.'/excerpt?accountNumber='.$accountNumber.'&from='.$from_date.'&till='.$till_date; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL,$curlURL); curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); curl_setopt($ch, CURLOPT_USERPWD, $user . ":" . $pass); curl_setopt($ch, CURLOPT_HEADER, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_POST, false); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET'); curl_setopt($ch, CURLOPT_POSTFIELDS,http_build_query($params)); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_VERBOSE, true); $curl_res = curl_exec($ch); if($curl_res) { $server_output = json_decode($curl_res); } $IE_Edge_pos_start = strpos ($curl_res, 'IE=Edge', 0); $IE_Edge_pos_start = $IE_Edge_pos_start + 7; $tinkoff_json = mb_substr($curl_res, $IE_Edge_pos_start); $tinkoff_json = trim($tinkoff_json); $tinkoff_json = json_decode($tinkoff_json); //     ,  ;) foreach ($tinkoff_json as $k=>$v){ if($k=='accountNumber'){ if(!($v==$accountNumber)) die('not that accountNumber'); } } //$tinkoff_array -    json   foreach ($tinkoff_json as $k=>$v){ if($k=='operation'){ $i=0; foreach ($v as $t=>$s){ foreach ($s as $e=>$f){ $tinkoff_array[$i][$e]=$f; } $i++; } } } //   $tinkoff_array    for ($i=0;$i<count($tinkoff_array);$i++){ $temp_id = $pdo->query("SELECT count(*) FROM `justtin`.`tinkoff` WHERE id=".$tinkoff_array[$i]['id'].";")->fetchColumn(); if ($temp_id==0){ if (Get_highly_likely_is_number_bill($tinkoff_array[$i]['paymentPurpose'])!=""){ $stmt = $pdo->prepare("INSERT INTO `justtin`.`tinkoff` (id, date, amount, drawDate, payerName, payerInn, payerAccount, payerCorrAccount, payerBic, payerBank, chargeDate, recipient, recipientInn, recipientAccount, recipientCorrAccount, recipientBic, recipientBank, operationType, uin, paymentPurpose, creatorStatus, payerKpp, executionOrder, date_of_save) VALUES (:id, :date, :amount, :drawDate, :payerName, :payerInn, :payerAccount, :payerCorrAccount, :payerBic, :payerBank, :chargeDate, :recipient, :recipientInn, :recipientAccount, :recipientCorrAccount, :recipientBic, :recipientBank, :operationType, :uin, :paymentPurpose, :creatorStatus, :payerKpp, :executionOrder, NOW())"); $stmt->bindParam(':id', $tinkoff_array[$i]['id']); $stmt->bindParam(':date', $tinkoff_array[$i]['date']); $stmt->bindParam(':amount', $tinkoff_array[$i]['amount']); $stmt->bindParam(':drawDate', $tinkoff_array[$i]['drawDate']); $stmt->bindParam(':payerName', $tinkoff_array[$i]['payerName']); $stmt->bindParam(':payerInn', $tinkoff_array[$i]['payerInn']); $stmt->bindParam(':payerAccount', $tinkoff_array[$i]['payerAccount']); $stmt->bindParam(':payerCorrAccount', $tinkoff_array[$i]['payerCorrAccount']); $stmt->bindParam(':payerBic', $tinkoff_array[$i]['payerBic']); $stmt->bindParam(':payerBank', $tinkoff_array[$i]['payerBank']); $stmt->bindParam(':chargeDate', $tinkoff_array[$i]['chargeDate']); $stmt->bindParam(':recipient', $tinkoff_array[$i]['recipient']); $stmt->bindParam(':recipientInn', $tinkoff_array[$i]['recipientInn']); $stmt->bindParam(':recipientAccount', $tinkoff_array[$i]['recipientAccount']); $stmt->bindParam(':recipientCorrAccount', $tinkoff_array[$i]['recipientCorrAccount']); $stmt->bindParam(':recipientBic', $tinkoff_array[$i]['recipientBic']); $stmt->bindParam(':recipientBank', $tinkoff_array[$i]['recipientBank']); $stmt->bindParam(':operationType', $tinkoff_array[$i]['operationType']); $stmt->bindParam(':uin', $tinkoff_array[$i]['uin']); $stmt->bindParam(':paymentPurpose', $tinkoff_array[$i]['paymentPurpose']); $stmt->bindParam(':creatorStatus', $tinkoff_array[$i]['creatorStatus']); $stmt->bindParam(':payerKpp', $tinkoff_array[$i]['payerKpp']); $stmt->bindParam(':executionOrder', $tinkoff_array[$i]['executionOrder']); $stmt->execute(); } } } } 

Readers: I hope this material will help in the monetization of your web services and services of your customers. May the force be with you!

To the guys from technical support of Bank Tinkoff: I hope this article will reduce the load on you! Good luck!

Source: https://habr.com/ru/post/431908/


All Articles