How to Create a Mint Import CSV of Transactions Using Python

Trying to upload transactions to Mint using a CSV and Python? Find the source code and examples on Github.

Why You Might Need to Add Transactions into Mint

To create a budget you are going to want data to base spending habits on. While mint.com allows for up to a 3-month auto-import, it is not guaranteed. This also neglects periodic purchases like new brakes or tires for your car.

The whole reason to have Mint is to be able to see all the data in one place. All in all, let’s face it: The software’s “from 30 to 90 days” just doesn’t cut it for new users.

My Search for Tools that do Mint Import Transactions

Having worked in technology for as long as I have, I knew I could not be the only one with this problem. So I immediately went on Google to see if there was anyone else who had solved this issue for me.

Low and behold, I did find a YouTube video of a proof of concept approach for automating manual transactions with a plug for their premium product. There was no code available though, so I would have to reverse engineer that myself.

Not wanting to totally start from scratch, I figured I’d check out GitHub too. I stumbled upon some similar code specifically for the UK locale and date formats. It was clearly written by someone else like me who had a one-off problem and decided to solve it themselves.

The code did lack some features and process clarity that I needed, so I figured I’d write my own version with the documentation where other people could easily extend or augment it for themselves in the future.

My Python 3 Import CSV Tool

First, I had to pick a language to write this tool in. At the time of writing this article, I have had professional experience in Java, Javascript, PHP, Ruby, Python, LUA, and Bash.

I chose Python for the ease of use of an interpreted language (one that is compiled on the fly by the machine, not the user) and the ease of PIP for extending functionality for things like CSVs.

Python Package Dependencies

We are going to need the following Python packages for our script. For those not familiar with installing packages via PIP, we have included instructions in the import.py documentation.

"""
#################################
Pre-requisites needed
#################################
If you are missing any of the following you can install with:
	pip install $name
	Example: pip install csv 
OR if you are using pip3
	pip3 install $name 
	Example: pip3 install csv 
"""

import csv
import datetime
import os
import random
import requests
import time
import urllib.parse
  • CSV – used to parse the input file
  • datetime – used to manipulate date strings and objects
  • os – used to interact with our local machine
  • random – used to implement random numbers
  • requests – used to submit HTTP requests (note we are actually just using curl right now)
  • time – used to interact with time strings and objects
  • urllib – used to HTTP encode strings so they can be submitted over POST and form data

Process to Importing Transactions

  1. Upload CSV data to python
  2. Process date for correct format and HTTP encode the result
  3. Process merchant text for HTTP encode
  4. Process categories and change your bank’s category name into a Mint category ID (limited in scope based on the categories I needed when I wrote this)
  5. Process amount for positive or negative value, indicating the transaction data is income or an expense
  6. Create CURL string post request
  7. Send POST Request to Mint as new transaction data.
  8. Force Randomized Wait Time before starting next request

Setting Up a Mint CSV Import Client

Because there is no public Mint API, we are going to need to find a way to mimic manual transaction adds using the UI’s form post.

William Lorfing (Intuit Developer Group)3 years ago

There are no APIs to access Mint data.

Mint HelpDesk as of 05/04/20

To do this we are going to need to use your browsers DevTools:

"""
#################################
Mint Client Credentials 
#################################
You will need the tags, cookie, and token to simulate a UI form submission. You can get these by opening developer tools > network analysis tab and doing 
a test submission in mint.com. From there look for the post request to "updateTransaction.xevent" and grab the credentials from the header and body
"""
account = 'XXXXXXX' # grab from POST request form body in devtools
tag1 = 'tagXXXXXX' # in form of tagXXXXXXX
tag2 = 'tagXXXXXXX' # in form of tagXXXXXXX
tag3 = 'tagXXXXXXX' # in form of tagXXXXXXX
cookie = 'XXXXXXX' # grab from POST request header in devtools 
referrer = 'XXXXXXX' # grab from POST request header in devtools 
token = 'XXXXXXX' # grab from POST request form body in devtools
  1. Go to Mint and login
  2. Go to transactions and click “+transaction”
  3. Open your DevTools (F12 on Chrome) and go to Network Tab
    1. Chrome DevTools - Network
  4. Submit a TEST transaction for $0.01, the network analysis tab will record the POST submission under “updateTransaction.xevent”
    1. Submit Mint Transaction
  5. Click on “updateTransaction.xevent” and you can see the headers of your request. Specifically, you will want the “request headers” for the cookie and the “form data” for things like tags and your token.

Setting Up a Bank’s Transactions CSV

Each bank will have a different way to get your transactions as CSV data. If your bank really doesn’t have this functionality,

  1. Get a new bank 😉
  2. Reach out to support as ask for a CSV file
  3. If they won’t do that, you can manually extract and copy the data into a spreadsheet, transform it into CSV format, then load it in (this is beyond the scope of this article, but we’ll have an article on scraping and text transformations later).

**STRONG RECOMMENDATION**
If you are uploading thousands of transactions like I did, you are going to want to sort your CSV by transaction date. This will allow you to retry from where it left off in the event of a failure.

What is important is understanding the format that the program expects. My script is based on a Chase.com CSVs export. If your bank uses a different format, you can adjust the column maps OR scrub it to match.

To those not familiar with reading Python, row[X] means the item X from left to right of that row starting with number 0. In my script, the first column must be the date of the transactions, followed by post date, merchant memo, categoryID, typeID, and amount of transaction (signed +-).

	# Initialize Variables
	date = (row[0]) 
	postDate = (row[1])
	merchant = (row[2])
	catID = (row[3])
	typeID = (row[4])
	amount = (float(row[5]))

Adding Transaction Categories

One of the main areas I did not fully develop is in category mapping. Mint requires you to use categoryIDs and names defined by them, which means the ones from your bank will not work. To deal with this, I have implemented two functions:

# Category ID Mapping Function 
	def category_id_switch(import_category):

category_id_switch maps the Chase named categories to Mint category ids. To make this match your bank’s categories, you just change the keys like “Credit Card Payment” to whatever your bank calls it. To add additional category support, I have included Mint’s category menu in html format as of 05/04/20 where you can grab the category names and ids from the markup.

# Category NAME Mapping Function 
	def category_name_switch(mint_id):

def category_name_switch maps Mint category ids to their Mint names. To add additional category support I have included Mint’s category menu in html format as of 05/04/20 where you can grab the category names and ids from the markup.

There was only one special case in my 1,800 transactions, and that is when Chase’s type = “payment”. In these scenarios, we had to handle them as catID 2101 in Mint. If your bank uses a different payment category, you can either comment this code out or map it to a category of your choosing.

# typeID payment overrides all categories 
	if typeID == "Payment":
		catID = '2101' # Since I was importing credit cards I have mine set to credit card payment. If you are doing bank accounts you many want to change this to payment general

Running CSV Import

Once you’ve got your client all setup and your category maps set all you need to do is run the following command from the directory your code and the CSV are in:

python3 import.py

OR if you are not using the python3 namespace

python import.py

That is it! You can sit back and watch the transactions add into your profile.

Summary
software image
Author Rating
1star1star1star1stargray
Aggregate Rating
5 based on 36 votes
Software Name
Mint CSV Importer
Operating System
MacOS, Linux, Windows with Cygwin
Software Category
Finance and Accounting
Price
USD 0.00
Landing Page
Share This:

12 thoughts on “How to Create a Mint Import CSV of Transactions Using Python”

  1. FYI, I was playing around with the “category menu in HTML format” you published to see if I could generate a complete list of categories and IDs. I noticed there are several categories with an ID beginning with “1963”. These categories are 7 digits long and have some oddly specific names. My guess is they’re custom categories you added to mint.

    I did manage to make a full list and added it into your import.py switcher. I’ll put it up on github when I get it working.

  2. Almost got this to work but not quite…the category name was always being set to “Uncategorized” because the catID was stringified before the lookup. Solved this by stringifying after setting category. The second problem is, the curls look successful (response 0) but I do not see the transactions appear in my account. The HTTP location shows ‘internalError.event’, but not sure what that means.

    HTTP/2 302
    date: Fri, 14 Aug 2020 06:53:53 GMT
    content-length: 0
    location: http://mint.intuit.com/internalError.event
    server: Mint App
    x-frame-options: SAMEORIGIN
    cache-control: no-cache, no-store, must-revalidate,
    expires: 0
    pragma: no-cache
    x-is-fdp-user: true
    x-mint-start: 1597388033155
    x-mint-end: 1597388033166
    content-language: en-US
    strict-transport-security: max-age=16000000; includeSubDomains; preload;
    x-xss-protection: : 1;mode=block
    x-content-type-options: : nosniff

    1. @christine HTTP/2 302 means you were redirected to there. Since this is mimic’ing front end UI not a real API my assumption would be your credentials expired and it was trying to bounce you somewhere else rather than 403 you. Obviously for security reasons do not post your token in here, will check to see if I can replicate this on my version today.

      A good way to check to see if this is the case is to just do a single curl using command line, if that works all the script does is duplicate that same request.

      1. I am getting same issue as well..Executing single curl command gives same issue as well. Also, I removed accountId from referrer query as mint seems to be not having that any more in its request and form body..Adding referrer to command results in same outcome..

        Here is my curl command (I removed Cookie and token :-))

        curl -i -s -k -X POST ‘https://mint.intuit.com/updateTransaction.xevent’ -H ‘Host: mint.intuit.com’ -H ‘User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36’ -H ‘Accept: */*’ -H ‘Accept-Language: en-US,en;q=0.5’ –compressed -H ‘X-Requested-With: XMLHttpRequest’ -H ‘Content-Type: application/x-www-form-urlencoded; charset=UTF-8’ -H ‘Referer: https://mint.intuit.com/transaction.event‘ -H ‘Cookie: ‘ -H ‘Connection: close’ –data ‘cashTxnType=on&mtCheckNo=&tag2917210=0&tag2917209=0&=0&task=txnadd&txnId=%3A0&mtType=cash&mtAccount=10866214&symbol=&note=&isInvestment=false&catId=20&category=Imported&merchant=Citi%3A%20AMAZON%20MKTPLACE%20PMTS%20AMZN.COM/&date=1/16/17&amount=-4.88&mtIsExpense=true&mtCashSplitPref=2&token=’

        HTTP/2 302
        date: Sat, 26 Sep 2020 12:43:07 GMT
        content-length: 0
        location: http://mint.intuit.com/internalError.event
        server: Mint App
        x-frame-options: SAMEORIGIN
        cache-control: no-cache, no-store, must-revalidate,
        expires: 0
        pragma: no-cache
        x-is-fdp-user: true
        x-mint-start: 1601124187536
        x-mint-end: 1601124187545
        content-language: en-US
        strict-transport-security: max-age=16000000; includeSubDomains; preload;
        x-xss-protection: : 1;mode=block
        x-content-type-options: : nosniff

  3. I keep getting a 255 curl response. When I try and run a single curl statement from the terminal, I get “xxx is not recognized as an internal or external command” where xxx is a string from the cookie.

Leave a Reply

Your email address will not be published. Required fields are marked *