-
-
Save brinko99/b8e3df3a97a8aec113e1385e6cbc976b to your computer and use it in GitHub Desktop.
// Submits CSV based transations to Mint as cash transaction. | |
// Used Chrome browser Developer Tools to get your custom cookies, token, etc. as cURL. | |
// For converting cURL to C# see: https://curl.olsh.me/ | |
// I used LinqPad to run the code. | |
// | |
// Inspired by: Mint batch transaction import hack | Blog | Vote Charlie | |
// https://votecharlie.com/blog/2017/06/mint-batch-transaction-import-hack.html | |
var handler = new HttpClientHandler(); | |
handler.UseCookies = false; | |
// If you are using .NET Core 3.0+ you can replace `~DecompressionMethods.None` to `DecompressionMethods.All` | |
handler.AutomaticDecompression = DecompressionMethods.None; | |
// CSV in format of <date>,<merchant>,<price> | |
using (var filestream = new StreamReader(@"C:\temp\transactions.csv")) | |
using (var httpClient = new HttpClient(handler)) | |
{ | |
int count = 0; | |
string line; | |
while ((line = filestream.ReadLine()) != null) | |
{ | |
// Uncomment for single test transaction, be sure to delete from .csv if successful | |
//// if (count++ >= 1) | |
//// { | |
//// break; | |
//// } | |
var lineSplit = line.Split(','); | |
if (lineSplit.Length != 3) | |
{ | |
Console.WriteLine($"Failed CSV format: '{line}'"); | |
continue; | |
} | |
// Encode date | |
string date = DateTime.Parse(lineSplit[0]).ToString("MM/dd/yyyy"); | |
date = System.Web.HttpUtility.UrlEncode(date); | |
// Encode merchant (my bank, chase used all uppers for merchants, converting to TitleCase) | |
string merchant = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(lineSplit[1].Replace(" ", " ").ToLower()); | |
// Adding prefix to easily find within Mint | |
merchant = $"Chase: {merchant}"; | |
merchant = System.Web.HttpUtility.UrlEncode(merchant); | |
string price = lineSplit[2]; | |
// Optional note | |
string note = "Imported from Chase"; | |
note = System.Web.HttpUtility.UrlEncode(note); | |
// Copy your content string. | |
// Note formatting placeholds {0}, {1}, {2}, {3} for date, merchant, price, and note respectively | |
string unformattedContent = "cashTxnType=on&mtCheckNo=&tag416803=0&tag693949=0&tag416804=0&tag416805=0&task=txnadd&txnId=%3A0&mtType=cash&mtAccount=<my account>&symbol=¬e={3}&isInvestment=false&catId=20&category=Uncategorized&merchant={1}&date={0}&amount={2}&mtIsExpense=true&mtCashSplitPref=2&token=<my token>"; | |
string formattedContent = string.Format(unformattedContent, date, merchant, price, note); | |
// https://curl.olsh.me/ will provide these details for your specific Mint session. Likely the results will be vary similar but may change over time; the cookie will be unique to you | |
using (var request = new HttpRequestMessage(new HttpMethod("POST"), "https://mint.intuit.com/updateTransaction.xevent")) | |
{ | |
request.Content = new StringContent(formattedContent); | |
request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/x-www-form-urlencoded; charset=UTF-8"); | |
request.Headers.TryAddWithoutValidation("Connection", "keep-alive"); | |
request.Headers.TryAddWithoutValidation("X-Requested-With", "XMLHttpRequest"); | |
request.Headers.TryAddWithoutValidation("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36"); | |
request.Headers.TryAddWithoutValidation("Accept", "*/*"); | |
request.Headers.TryAddWithoutValidation("Origin", "https://mint.intuit.com"); | |
request.Headers.TryAddWithoutValidation("Sec-Fetch-Site", "same-origin"); | |
request.Headers.TryAddWithoutValidation("Sec-Fetch-Mode", "cors"); | |
request.Headers.TryAddWithoutValidation("Referer", "https://mint.intuit.com/transaction.event"); | |
request.Headers.TryAddWithoutValidation("Accept-Encoding", "gzip, deflate, br"); | |
request.Headers.TryAddWithoutValidation("Accept-Language", "en-US,en;q=0.9"); | |
request.Headers.TryAddWithoutValidation("cookie", "<my very long cookie text>"); | |
var response = await httpClient.SendAsync(request); | |
if (response.IsSuccessStatusCode == false) | |
{ | |
Console.WriteLine($"Failed: {line}"); | |
} | |
} | |
} | |
} |
Hey brinko,
Thanks for putting this together. I just read through the article on votecharlie.com but unfortunately, I was not able to figure it out.
Do you think you could put together a quick guide on how to do this?
I would greatly appreciate it, I recently just lost all my historical data from my account. Mint has no idea where it went, but they can't fix they say.
Completely understand if your not interested, just thought I'd ask.
Thanks,
Kevin
Thanks... I did the best I can do for now with the code comments and screenshots. If you can capture test transactions with Chrome per the screenshots, use https://curl.olsh.me/ to generate the C#. Be sure to to test your code with a single transaction at a time before running it through your whole .csv. Deleting transactions via Mint's UI is a pain.
Sorry for not being able to put together something more thorough.
Good luck.
Inspired by Mint batch transaction import hack | Blog | Vote Charlie. See the blog for more details.
I used Chrome's Developer tools to capture the relevant POST transaction. See images below: