Skip to content

Instantly share code, notes, and snippets.

@brinko99
Last active July 26, 2020 02:50
Show Gist options
  • Save brinko99/b8e3df3a97a8aec113e1385e6cbc976b to your computer and use it in GitHub Desktop.
Save brinko99/b8e3df3a97a8aec113e1385e6cbc976b to your computer and use it in GitHub Desktop.
C# Mint Import of CSV data
// 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=&note={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}");
}
}
}
}
@brinko99
Copy link
Author

brinko99 commented Jul 7, 2020

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:

MintChrome01

MintChrome02

@Kevin1887
Copy link

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

@brinko99
Copy link
Author

@Kevin1887

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment