Tagline

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.

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

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.

1# Services/NetworkService
2
3import Foundation
4
5class NetworkService {
6  
7  enum Method: String {
8    case recurringExpenditures = "recurring_expenditures"
9  }
10  
11  var token: String {
12    return <#insert token here#>
13  }
14  
15  var baseURL: String = "https://api.pave.dev/v1"
16
17  var userId: String = <#insert user_id here#>
18  
19   
20}

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

1func performRequest(_ request: NetworkService.Method, completion: @escaping NetworkServiceCompletion) {
2    let url = URL(string: "\(baseURL)/users/\(userId)/\(Method.recurringExpenditures.rawValue)")!
3    var request = URLRequest(url: url)
4    request.httpMethod = "GET"
5    request.addValue("application/json", forHTTPHeaderField: "Content-Type")
6    request.addValue(token, forHTTPHeaderField: "x-api-key")
7    
8    let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
9      guard let response = response as? HTTPURLResponse else {
10        completion(.failure(.networkError(description: "No network")))
11        return
12      }
13      if let data = data, response.statusCode == 200 {
14        completion(.success(data))
15      } else if let error = error {
16        completion(.failure(.networkError(description: error.localizedDescription)))
17      } else {
18        completion(.failure(.codeNot200(code: response.statusCode)))
19      }
20    }
21    
22    task.resume()
23  }

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

1{
2    "user_id": "user_123",
3    "from": "2017-07-31",
4    "to": "2019-08-01",
5    "recurring_expenditures": [
6        {
7            "type": "Utility",
8            "normalized_merchant_name": "Comcast",
9            "merchant_uuid": "MERCHANT_ID",
10            "logo": "https://assets.pave.dev/merchants/logos/0002e1ce-e901-4715-bd9a-xxxxxxxxxxxx.png",
11            "last_amount": 184.78,
12            "last_description": "Comcast",
13            "last_date": "2019-07-30",
14            "avg_amount": 181.23,
15            "iso_currency_code": "USD",
16            "count": 24,
17            "avg_period_days": 30.7,
18            "normalized_frequency": "monthly",
19            "previous_amount": 184.78,
20            "previous_date": "2019-07-01",
21            "delta_amount": 0.0,
22            "delta_percent": 0.0
23        }, 
24        ...
25    ]
26}

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

1  // Dashboard/ExpensesDashboardPresenter.swift
2
3  func getExpenses(for date: Date) {
4    dataProvider.getExpenses() { [weak self] (result: Result<[Expenditure], Error>) in
5      guard let self = self else {return}
6      switch result {
7      case .failure(let error):
8        self.view.showError(error)
9      case .success(let result):
10        let transactionsSortedByDate = result.sorted { $0.lastTransactionDate > $1.lastTransactionDate }
11        
12        guard let monthToShow = transactionsSortedByDate.first?.lastTransactionDate else {
13          self.view.showError(SimpleError(errorDescription: "You have no transactions"))
14          return
15        }
16        
17        let (previousMonthExpenses, currentMonthExpenses) = self.processTwoLastMonthsExpenses(transactionsSortedByDate, currentDate: monthToShow)
18        self.currentMonthExpenses = currentMonthExpenses
19        self.previousMonthExpenses = previousMonthExpenses
20        
21
22        for expenditure in currentMonthExpenses.allExpenditures {
23          switch expenditure.category {
24          case .subscription:
25            self.currentMonthExpenses.subscriptions.append(expenditure)
26          case .bill, .utility, .rent, .other:
27            self.currentMonthExpenses.bills.append(expenditure)
28          }
29        }
30        self.view.updateData()
31      }
32    }
33  }

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!

Subscribe to newsletter

Subscribe to receive the latest blog posts to your inbox every week.

By subscribing you agree to with our Privacy Policy.
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.