We obtain the statistics of expenses by MCC: Tinkoff and Roketbank

  • Tutorial


Introduction


MCC (Merchant Category Code) is a merchant category code used in bank card transactions. According to this code, the bank determines which product the customer has purchased. It depends on him, you will receive a cashback, commission or cancel the grace period.


In an age when companies make money on data collected from users, it’s a sin not to take advantage of the reverse: to use information about yourself collected by companies so that, if you don’t make money from it, then at least save.


Knowing how much money you spend on each MCC code, you can calculate which bank card will bring great benefits. Therefore, if you used Tinkoff or Rocketbank cards for a sufficient time, this article will be useful to you in order to get statistics on expenses for each MCC.


Tinkoff


Tinkoff Bank's personal account shows the MCC operations when you click on it.



So you can see a dozen operations, but if we need to collect statistics for all the time the card is used, this business should be automated. Let's try to get the data in a convenient form for software processing.


UPD: As Smasher noted , the personal account provides the ability to upload all operations in CSV or Excel format. So, under the spoiler, a description of how I did it without knowing it.



Going the hard way

This will require the development tools of the browser, and specifically - the analysis of network activity (tab Network in Google Chrome). If you enable the analyzer and after that ask your personal account to display the operations “For all time”, then we will quickly find the desired request.



You can see that the server really gave the data for all the time, and the JSON response contains the required MCCs.



Для удобства обработки данных сымитируем запрос на Python. Я использую Jupyter Notebook.



Отправим POST-запрос на URL https://api.tinkoff.ru/v1/grouped_requests с идентичными параметрами sessionid и _methods и данными requestsData.


import requests
session_id = "b785Q2R5US2AZo2p5JoCtNQNkbmYsJbl.ds-api02"
methods = "operations" # нас интересует получение только операций, payments не нужны
params = {'sessionid': session_id, '_methods': methods}
# не мудрствуя лукаво просто скопируем requestsData из запроса
requests_data = '[{"key":0,"operation":"operations","params":{"wuid":"28a44beaeee7460b94dbdd0aa0dc935a","account":"5059373083","start":1136062800000,"end":1529269199999}}]'
data = {'requestsData': requests_data}
response = requests.post('https://api.tinkoff.ru/v1/grouped_requests', params=params, data=data)

Если мы всё правильно сделали, то ввод response.text в консоли выведет тело ответа. Осталось разобрать эти данные и сохранить нужные нам фрагменты.


import csv
operations = []
payload = response.json()['payload']
for key in payload:
    feed = payload[key]['payload']
    for operation in feed:
        mcc = operation['mcc']
        # MCC со значениями < 100 используются банком для операций не связанных с покупками
        if (mcc > 100):
            # если наименование магазина не указано, возьмём описание операции
            if 'merchant' in operation:
                merchant_name = operation['merchant']['name']
            else:
                merchant_name = operation['description']
            # в accountAmount отображается стоимость покупки в «родной» валюте
            cost = operation['accountAmount']['value']                
            operations.append((mcc, cost, merchant_name))
            print(mcc, cost, merchant_name)
# выведем всё в csv
output = open("tinkoff.csv",'w')
wr = csv.writer(output)
for item in operations:
    wr.writerow(item)

На выходе получим таблицу из MCC-кодов, стоимостей покупок и наименований магазинов.


Roketbank


Rocketbank shows MCC operations in the receipt. Therefore, we will need to collect references to the receipt of all transactions.



With Roketbank a little more difficult, because access to your personal account is carried out only through a mobile application. I will tell only about what earned me, and only about Android. Install the Charles analyzer on the computer and skip the traffic from the phone through it.


For this phone and computer must be connected to the same network. You will need to know the IP of the computer on the local network. For example, using ifconfig .


Next, we configure the phone to work through the proxy server Charles. In Android 7.0, this is done in the Wi-Fi settings with a long press on the connected network. Specify the computer's IP and port 8888, the default used by Charles.



It goes without saying that the Roketbank application uses TLS when interacting with the server and we simply cannot listen to the traffic. Charles supports traffic interception with TLS certificate substitution, that is, it implements a MITM attack. However, for this, the device must trust the Charles root certificate.


Charles root certificate is installed when you follow the link https://chls.pro/ssl from a mobile device with proxying enabled. In addition, you need to add rocketbank.ru to the list of proxied hosts in Proxy -> SSL Proxying Settings .



But this will not be enough, because in Android 7.0, by default, applications do not trust user certificate authorities. Security! The application must be compiled with the appropriate permission. Let? Never. We decompile and compile as we need.


First we get the application package from the phone. This can be done using the Android Debug Bridge or the Apk Extractor application . The first method did not work on Android 7.0, and the second handled the task.


We take the package to the computer and decompile with apktool .


apktool d rocket.apk 

You need to add a network security configuration file at res / xml / network_security_config.xml. More information about the format of the configuration file can be read here , we have enough of the following settings:


<network-security-config> 
  <base-config> 
    <trust-anchors> 
      <!-- Always trust user added CAs -->
      <certificates src="user" /> 
    </trust-anchors> 
  </base-config> 
</network-security-config> 

This configuration file must be specified in the application manifest (AndroidManifest.xml in the root) by adding the android: networkSecurityConfig parameter to the application tag.


<application android:networkSecurityConfig="@xml/network_security_config" android:allowBackup="false" ...>...</application>

Now compile.


apktool b rocket

It remains to sign the application, since unsigned applications are not installed. We use for this program to sign with a built-in test certificate .


java -jar sign.jar rocket.apk

Delete the original Roketbank application from the phone, copy the modified package to the phone and install (for example, through the Files application).


Now Charles traffic interception should work. Open the Roketbank application, log in and look at Charles. Here it is, our link to the receipt.



Let's go back to Python again and simulate this GET request, but we won’t waste time on trifles and ask the server to give us data about all operations. Well, or at least about the first 999999.


token = 'c8ccb54b-09e3-4608-a5b4-7914a92c21f3206582'
params = {'token': token, 'page': 1, 'per_page': 999999}

It was experimentally found out that the server trusts the session only if the correct x-device-id , x-time and x-sig are sent along with the token . We don’t feel sorry, because you don’t have to invent anything and count, just copy it.


x_device_id = 'ANDROID_C6FBB57CD433E756_899EE771-4AC5-46ED-44A1-656CE47A417B'
x_time = '1529194008'
x_sig = 'c486365013ddebe8b7f4599afbf73d26'
headers = {'x-device-id': x_device_id, 'x-time': x_time, 'x-sig': x_sig}
response = requests.get('https://rocketbank.ru/api/v5/operations/sexy_feed', params=params, headers=headers)

For pulling the MCC from the receipt will be enough regulars. We run over the operations, read the receipt, run it through the regular season and everything we need in our pocket.


import re
regex = re.compile('MCC:</dt><.+?>(\d+)</dd>')
operations = []
feed = response.json()['feed']
for item in feed:
    if item[0] == 'operation':
        operation = item[1]
        merchant_name = operation['merchant']['name']
        receipt_url = operation['receipt_url']
        cost = operation['money']['amount']
        # считаем только расходы
        if cost < 0:
            receipt = requests.get(receipt_url)
            match = regex.search(receipt.text)
            if match is not None:
                mcc = match[1]
                operations.append((mcc, -cost, merchant_name))
                print(mcc, -cost, merchant_name)
            else:
                # если MCC не найден, то запишем вместо него название магазина,
                # так как оплата услуг проходит без указания MCC
                operations.append((merchant_name, -cost))
                print(merchant_name, -cost)
output = open("rocket.csv",'w')
wr = csv.writer(output)
for item in operations:
    wr.writerow(item)

Perhaps you can remove the modified application and set back the original one.


Total


Combining data from two banks, grouping operations by MCC using a pivot table (Pivot Table), manually cleaning the data from transfers and withdrawing cash and grouping them into similar categories in places, I got the following picture:



Now, using a service like mcc-codes.ru , you can pick up cards with an increased cashback for the most expensive categories. And, correlating the amount of possible cashback with the cost of annual maintenance, determine whether it is advisable to issue a specific card.


What is the benefit of it? With my spending and the correct selection of cards can save 10 thousand rubles a year. Is it worth it? You decide :)


Also popular now: