How to build bill & subscription tracking in hours

With our Cashflow API, it is simple to retrieve and display a user’s bills and subscriptions.

We wrote a separate post that goes into the use cases that can be built on this information.

You can view the entire example in our github repo. This example uses the recurring expenditures endpoint to generate a list of user’s bills and subscriptions as well as generate some useful analysis, such as changes in your bills and subscriptions over time.



We’ll be making the following assumptions in this post:

  • You already have access to the Cashflow API.
  • You have already uploaded sample data to
  • If either of these assumptions does not hold for you, please contact us at

Technologies Used

  • Swift – This example was built entirely in swift
  • CocoaPods – For dependency management

We’re going to cover the following in this post:

  1. Implementing the HTTP API
  2. Building a dashboard with recurring expenditures data

Step 1: Implement our HTTP API

If you’re following along with our github example, you need only update the user id and the API key in the code snippet below. In a production scenario, these values would come from a database or a secrets store.

# Services/NetworkService

import Foundation

class NetworkService {
  enum Method: String {
    case recurringExpenditures = "recurring_expenditures"
  var token: String {
    return <#insert token here#>
  var baseURL: String = ""

  var userId: String = <#insert user_id here#>

Once you’ve updated these two values, you can now call the recurring expenditures API

func performRequest(_ request: NetworkService.Method, completion: @escaping NetworkServiceCompletion) {
    let url = URL(string: "\(baseURL)/users/\(userId)/\(Method.recurringExpenditures.rawValue)")!
    var request = URLRequest(url: url)
    request.httpMethod = "GET"
    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
    request.addValue(token, forHTTPHeaderField: "x-api-key")
    let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
      guard let response = response as? HTTPURLResponse else {
        completion(.failure(.networkError(description: "No network")))
      if let data = data, response.statusCode == 200 {
      } else if let error = error {
        completion(.failure(.networkError(description: error.localizedDescription)))
      } else {
        completion(.failure(.codeNot200(code: response.statusCode)))

You should get a JSON response that looks something like this:

    "user_id": "user_123",
    "from": "2017-07-31",
    "to": "2019-08-01",
    "recurring_expenditures": [
            "type": "Utility",
            "normalized_merchant_name": "Comcast",
            "merchant_uuid": "MERCHANT_ID",
            "logo": "",
            "last_amount": 184.78,
            "last_description": "Comcast",
            "last_date": "2019-07-30",
            "avg_amount": 181.23,
            "iso_currency_code": "USD",
            "count": 24,
            "avg_period_days": 30.7,
            "normalized_frequency": "monthly",
            "previous_amount": 184.78,
            "previous_date": "2019-07-01",
            "delta_amount": 0.0,
            "delta_percent": 0.0

Step 2: Build the dashboard

We’re now ready to build the dashboard. As always, you can find the full implementation of this example app in our git repository. The following code separates expenses by spending category, and updates the dashboard view with data from the recurring expenditures api

  // Dashboard/ExpensesDashboardPresenter.swift

  func getExpenses(for date: Date) {
    dataProvider.getExpenses() { [weak self] (result: Result<[Expenditure], Error>) in
      guard let self = self else {return}
      switch result {
      case .failure(let error):
      case .success(let result):
        let transactionsSortedByDate = result.sorted { $0.lastTransactionDate > $1.lastTransactionDate }
        guard let monthToShow = transactionsSortedByDate.first?.lastTransactionDate else {
          self.view.showError(SimpleError(errorDescription: "You have no transactions"))
        let (previousMonthExpenses, currentMonthExpenses) = self.processTwoLastMonthsExpenses(transactionsSortedByDate, currentDate: monthToShow)
        self.currentMonthExpenses = currentMonthExpenses
        self.previousMonthExpenses = previousMonthExpenses

        for expenditure in currentMonthExpenses.allExpenditures {
          switch expenditure.category {
          case .subscription:
          case .bill, .utility, .rent, .other:

This should get you started with our API. We’re excited to see what you can build with our API. If you would like to try this yourself, you can request access to our Sandbox here.

Our Github Repo: is where you can see other use cases we have published to get you started with using our APIs. We have a ton of exciting use cases in our roadmap, so there’s a lot more to come!