How to build bill & subscription tracking in hours


Lennon Chimbumu
August 4, 2021

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.

Preview

images/ios-dashboard.png

Assumptions

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

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

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.

Copy
Copied
# Services/NetworkService

import Foundation

class NetworkService {
  
  enum Method: String {
    case recurringExpenditures = "recurring_expenditures"
  }
  
  var token: String {
    return <#insert token here#>
  }
  
  var baseURL: String = "https://api.pave.dev/v1"

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

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

Copy
Copied
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")))
        return
      }
      if let data = data, response.statusCode == 200 {
        completion(.success(data))
      } else if let error = error {
        completion(.failure(.networkError(description: error.localizedDescription)))
      } else {
        completion(.failure(.codeNot200(code: response.statusCode)))
      }
    }
    
    task.resume()
  }

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

Copy
Copied
{
    "user_id": "user_123",
    "from": "2017-07-31",
    "to": "2019-08-01",
    "recurring_expenditures": [
        {
            "type": "Utility",
            "normalized_merchant_name": "Comcast",
            "merchant_uuid": "MERCHANT_ID",
            "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

Copy
Copied
// 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):
        self.view.showError(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"))
          return
        }
        
        let (previousMonthExpenses, currentMonthExpenses) = self.processTwoLastMonthsExpenses(transactionsSortedByDate, currentDate: monthToShow)
        self.currentMonthExpenses = currentMonthExpenses
        self.previousMonthExpenses = previousMonthExpenses
        

        for expenditure in currentMonthExpenses.allExpenditures {
          switch expenditure.category {
          case .subscription:
            self.currentMonthExpenses.subscriptions.append(expenditure)
          case .bill, .utility, .rent, .other:
            self.currentMonthExpenses.bills.append(expenditure)
          }
        }
        self.view.updateData()
      }
    }
  }

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: https://github.com/Pave-Financial/pave-examples 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!



#subscriptions #bill tracking #transactions 

Copyright © Pave Financial 2021. All right reserved.