Lunch Money v2 API Initial Changelog

Introduction

Welcome to the v2 Lunch Money API. This API was built with help from our Developer Community and addresses many feature requests. including:

Goals For This Release

In addition to adding features requested by our developer community, we had several goals for this release:

Consistency

This update focuses on staying consistent in several key areas:

OpenAPI Specification

We followed a "Design First" approach for this version of the API. This means we planned and documented the API using a standard OpenAPI specification before we built anything. The same specification was then used to generate our documentation and the types used in the API itself.

This helps ensure that our documentation always stays in sync with how the API works. It also gives our Developer Community a reliable spec to build their own language-specific SDKs and other tools.

Consistent Error Behavior

We changed the way errors are handled so they follow standard RESTful API best practices. Error messages are now written to give you all the information you need to understand and fix the issue.

Atomic Operations
When the API returns a 4XX code, it generally means no part of the request was applied to your data. Examples include:
  • When inserting multiple transactions, if even one transaction has an error, none of them will be added.
    • Fix the issues in the error response, then try again without worrying about duplicates.
  • When modifying a category group, if any child categories are invalid, no changes will be made to the current children in the group.
    • Fix the issues in the error response and try again.

Generally, if a request has multiple issues, the error response will list as many as possible in the errors array. However, it’s not guaranteed that all errors will be caught in a single request.

Request Validation

We added strict request validation so developers can quickly catch mistakes while building. In general, a request will return a 400 response if:

ID Type Change
IDs are now specified as integer instead of number in the various request and response schemas to allow for better validation.

Object property naming conventions

We have attempted to name (or rename) object properties to apply consistent behavior as follows:

Standardized Success Status Codes and Response Bodies

Overwrite Potential
Unless otherwise documented, the values for complex properties, such as objects and arrays that are set in the request body of a PUT request, will completely replace any previous value for these properties. Therefore, if you wish to, for example, add a new tag to a transaction or a new child category to a category group, you should first query the existing object and then update the property appropriately.
Recommended Update Approach
Because request bodies MAY optionally contain "system-definable" properties, developers may perform PUT requests using the following pattern:
  • Make a GET /endpoint/{id} request.
  • Modify the "user definable" properties of the response to the GET request.
  • Make a PUT /endpoint/{id} request, passing in the complete modified object.

Versioning

The v2 Lunch Money API is versioned using a modified version of SEMVER as follows:

This initial public change log encapsulates the changes in the Lunch Money API from the v1 API to the initial public release of version v2.8.0 of the v2 API.

This document encapsulates the sum of changes vis-a-vis the v1 version of the API as of the initial release, but you can also view a detailed version history, which will be maintained going forward.

Endpoint Specific Changes

This section outlines elements that have changed from the existing v1 API behavior.

If you have an app that uses the v1 API you may wish to review these changes in the Migration Guide

The User Object

{
  "user_id": 123,
  "user_name": "John Doe",
  "user_email": "john@example.com"
}
{
  "id": 123,
  "name": "John Doe",
  "email": "john@example.com",
}

View v1/v2 differences

View v2 User Object Docs

The Category Object

Breaking Changes
  • The category object now has a collapsed property which may be set to true for Category Groups when the group has been collapsed in the Web UI.
  • The children property, which is present only when the is_group property is true, is no longer nullable.
    • The children property will always be the list of categories that belong to the group.
    • The Category Objects in the children property of a Category Group will always have value of false for is_group and will never have a children property.
    • Category Groups with no child categories will have a children property with an empty list, ie: [], and not null.
  • The group_category_name property which only existed under certain circumstances in the V1 API has been removed.

View v1/v2 differences

View v2 Category Object Docs

categories endpoints

GET /v1/categories?format=nested  // or "flattened" - default: flattened
GET /v2/categories  // Default: nested alphabetized list
GET /v2/categories?format=flattened  // All categories including duplicates
GET /v2/categories?is_group=false  // Only assignable categories (no groups)
GET /v2/categories?is_group=true   // Only category groups
Important Changes
  • The default response to this endpoint (with no query params) will be an alphabetized nested category list, where grouped categories are listed in the children property of the Category Group.
    • The length of the default response (or the response when format is set to nested) is NOT the total number of categories and category groups. It is the number of category groups and ungrouped categories.
  • When the optional format property is set to flattened, the response will be a list that includes all categories and category groups. Category groups will have a children property that is a list of category objects that belong to that category.
    • Grouped categories are represented twice in a flattened response.
    • The length of the flattened response is the total number of category and category groups.
  • The v1 endpoint only included the category_group_name (which is now renamed group_name) property for grouped categories in response when the flattened query parameter was set to nested
    • The group_name attribute is present only on categories that belong to a group
    • group_name will be present in all returned categories that belong to a group across all APIs and query parameter combinations
POST /v1/categories
{ "name": "Groceries", ... }
POST /v1/categories/group
{ "name": "Food & Drink", "category_ids": [...], ... }
POST /v2/categories
{ "name": "Groceries", ... }
// Returns: Full category object
POST /v2/categories
{ 
  "name": "Food & Drink", 
  "is_group": true, 
  "children": [...]  // Optional
}
// Returns: Full category group object with complete children
Response Changes
  • This endpoint now returns the newly created category or category group object in the response body when successful.
    • V1 version returned a boolean true if the category was created.
    • If a category group was created, the response will include complete category objects in the children array.
PUT /v1/categories/:id
// Returns: true
POST /v1/categories/group/:group_id/add
{ "category_ids": [1, 2, 3] }
PUT /v2/categories/:id
{ "name": "Updated Name", ... }
// Returns: Full updated category object
PUT /v2/categories/:id
{ "children": [1, 2, 3] }  // Replaces all children
// Returns: Full updated category group
Behavior Change
  • This single endpoint can be used to edit both categories and category groups.
  • It is not permitted to convert an existing category to a category group or vice versa; therefore, attempting to change the value of the is_group property of a category or category group will result in an error.
  • The children property specified will completely replace the existing child categories of the target category group.
    • To add children, you must include all desired children in the array.
DELETE /v1/categories/:id/force  // Force delete endpoint
// Returns: true or error with dependents object
DELETE /v2/categories/:id?force=true  // Use query parameter
// Returns: 204 No Content (success) or 422 with dependents (if has dependencies and force=false)
Response Changes
  • This endpoint now returns a 404 if the requested category id does not exist.
  • This endpoint now returns a 204 upon a successful delete. No response body is provided.
  • If the force parameter is not set to true and the requested category has dependencies, a 422 "Unprocessable Content" status is returned.
    • The response body will include a category_name property and a dependents property.

The Tags Object

View v1/v2 differences

View v2 Tag Object Docs

tags endpoints

New Capabilities
v2 adds full CRUD operations for tags. The v1 API only supported listing tags. View Docs
GET /v1/tags  // List only, no order guarantee
GET /v2/tags  // ✅ Alphabetical order (matches GUI)
GET /v2/tags/:id  // ✅ New
POST /v2/tags  // ✅ New
{ "name": "Work Expense", ... }
PUT /v2/tags/:id  // ✅ New
{ "name": "Business Expense", ... }
DELETE /v2/tags/:id  // ✅ New

The Transaction Object

The transaction object has changed significantly in v2. A transaction has properties that reference other objects in Lunch Money such as categories, accounts, and tags. In v1 the details for these related object were "hydrated". In the context of RESTful APIs, "hydration" generally refers to populating an object with all its data. In the Lunch Money APIs, hydration generally relates to providing the details of associated objects that are also referred to by their IDs in the response body.

Breaking Change: Dehydrated Responses
To optimize the responsiveness of the v2 Lunch Money APIs, the transaction object will no longer be hydrated. Categories, accounts, and tags are now returned as IDs only. Details of these objects can be retrieved by calling the appropriate endpoint using the supplied ID. Developers are encouraged to maintain a local cache of these objects to reduce the number of API calls.

Specific changes are:

Breaking Change: Transaction Amounts
  • The amount continues to be a string that represents the amount of the transaction in whatever currency is specified in the currency property of the transaction.
  • In the v1 API, the optional debits_as_negative query param controlled how to interpret the amount. If this parameter was set to false (the default), a negative amount value would indicate a credit transaction.
  • In the v2 API, this parameter is no longer supported and the value in the amount field is always positive for debit transactions and negative for credit transactions, regardless of how the user has set the "Show debits as negative, credits as positive" toggle in the user settings of the Web UI.

Migration: Modify existing code to expect that positive transaction amounts values are debit transactions, while negative values indicate credit transactions.

View v1/v2 differences

View v2 Transaction Object Docs

transactions endpoints

The transactions endpoint is one of the most complex in Lunch Money. To simplify the documentation, it is broken down into four subsections:

Endpoints that return or operate on a single transaction

Complete Details
This endpoint returns all the details associated with the requested object, including properties that are not returned by the bulk GET /transactions endpoint. These include:
  • plaid_metadata
  • custom_metadata
  • files
  • children - if the returned transaction has either the is_parent or is_group property set to true
PUT /v1/transactions/:id
{
  "transaction": { ... },
  "split": [...],              // ❌ Removed
  "debit_as_negative": false,  // ❌ Removed
  "skip_balance_update": true  // ❌ Renamed
}
PUT /v2/transactions/:id?update_balance=false  // Query parameter
{
  // Transaction properties to update
  // System properties like "id" or "updated_at" are ignored
}
Splitting Transactions
The split parameter has been removed. Use POST /transactions/split/{id} to split transactions instead.
New Feature
It is now possible to delete transactions via the API!
  • Grouped or split transactions must be ungrouped or unsplit before they can be deleted.
  • Returns a 204 No Content response when successful.

Endpoints that return or operate on an array of transactions

GET /v1/transactions
// Requests with no start_date and end_date return transactions for current month
GET /v1/transactions?pending=true
// Response will include pending transactions
GET /v2/transactions?debits_as_negative=true
// Query param controlled the sign of amounts for debits/credits
GET /v1/transactions
// Requests with no start_date and end_date returns all recent transactions
// Positive amount values indicate debit transactions,
// negative amount values indicate credit transitions.
GET /v2/transactions?include_pending=true
// Optional parameters:
// ?include_metadata            // Include plaid_metadata, custom_metadata
// ?include_files               // Include file attachments
// ?include_children            // Include children for split/grouped
// ?include_split_parents       // Include parent transactions
// ?include_group_children      // Include grouped transactions 
// ?created_since=2024-01-01   // Filter by creation timestamp (date or datetime)
// ?updated_since=2024-01-01T12:00:00Z  // Filter by update timestamp (date or datetime)
Performance Optimizations
To improve responsiveness, the following properties are not included in the returned Transaction Objects by default:
  • plaid_metadata / custom_metadata - enable via include_metadata
  • children - enable via include_children
  • files - enable via include_files

Parents of split transactions and grouped transactions are no longer returned by default, matching the GUI behavior.

New Filtering Options
The created_since and updated_since query parameters allow you to filter transactions based on when they were created or last updated:
  • Both parameters accept either a date (YYYY-MM-DD) or ISO 8601 datetime string
  • Date-only values are interpreted as midnight UTC (00:00:00Z)
  • Returns only transactions where created_at or updated_at is greater than the provided timestamp
  • These parameters work independently and can be used alone or together
  • Example: GET /v2/transactions?created_since=2024-01-01&updated_since=2024-01-15T10:00:00Z
New Feature: Bulk Updates
It is now possible to modify the properties of multiple transactions with a single API call.
New Feature: Bulk Delete
Submit a list of transaction ids to be deleted in a single request.
  • Grouped or split transactions must be ungrouped or unsplit before they can be deleted.
  • Returns a 204 No Content response when successful.
  • If any transaction ids are invalid, an array of errors will be returned.

Endpoints for grouping or ungrouping transactions

POST /v1/transactions/group
{ 
    "transactions": [id1, id2, ...],
    "tags": ["Work"],
    // other properties
}
POST /v2/transactions/group
{ 
    "ids": [id1, id2,...],  // ✅ Renamed from "transactions"
    "tag_ids": [1, 2],      // ✅ Renamed from "tags"
    "status": "unreviewed"  // ✅ New optional property
}
Property Renames
  • transactionsids
  • tagstag_ids
Response Change
This API now returns a 204 No Content on success (instead of 200 with transaction IDs). The transaction group is deleted and the transactions are restored to "normal" transactions.

Endpoints for splitting or unsplitting transactions

PUT /v1/transactions/:id
{ "split": [...] }
// Deletes existing children if already split
POST /v2/transactions/split/:id
{ "child_transactions": [
    // objects with at least "amount" and "payee" fields
] }
// Returns: Full transaction with is_parent: true and children array
// Fails if transaction already split
POST /v1/transactions/unsplit
{ "parent_ids": [...] }
DELETE /v2/transactions/split/:parent_id
// Returns: 204 No Content

The Transaction Attachment Object

The transactionAttachmentObject is a new object type that represents a file attached to a transaction. It has the following properties:

Endpoints for managing file attachments

New Feature
v2 introduces the ability to view, create and delete file attachments to transactions.

The Recurring Object

Major Reorganization
The recurring object has been significantly refactored from the recurring items object in v1. While there haven't been major changes to the properties that make up the object, they have been reorganized to provide greater clarity to their meaning.

Essentially the object's properties are organized into one of four categories:

  • Top Level properties are attributes of the recurring items itself such as id, description and source.
  • The transaction_criteria object contains the properties that are used to determine if a transaction matches the recurring item, such as payee, amount and an optional account id.
  • The overrides object contains properties that will be updated in matching transactions such as payee, notes and category_id
  • The matches object contains details about the dates that matching transactions are expected, the transaction_ids for transactions that are found, and the dates when transactions are expected, but have not been found

Specific changes are:

View v1/v2 differences

View v2 Recurring Object Docs

recurring endpoints

GET /v1/recurring_items?start_date=2024-06-01
// Returns: Reviewed items only
GET /v2/recurring_items?start_date=2024-06-01&end_date=2024-06-30  
// Both start and end are required if using dates
GET /v2/recurring_items?include_suggested=true
// Include suggested recurring items
GET /v2/recurring_items/:id  // ✅ New: Get single recurring item

The Manual Account Object (formerly Asset Object)

Endpoint Rename
The term asset which was used for an endpoint and an object that represented manually created accounts has been changed to simply manual_account.
{
  "type_name": "depository",  // ❌ Renamed
  "subtype_name": "...",      // ❌ Renamed
  "exclude_transactions": false  // ❌ Renamed
}
{
  "type": "cash",  // ✅ Renamed (depository → cash)
  "subtype": "...",  // ✅ Renamed
  "exclude_from_transactions": false,  // ✅ Renamed
  "updated_at": "...",  // ✅ New
  "external_id": "...",  // ✅ New (API-only)
  "custom_metadata": {}  // ✅ New (API-only, < 4MB)
}

View v1/v2 differences

View v2 Manual Account Object Docs

manual_accounts endpoints

The Plaid Account Object

The properties of the Plaid Account Object are unchanged from the v1 version of the API with the following exception:

View v1/v2 differences

View v2 Plaid Account Object Docs

plaid_accounts endpoints

Summary Endpoint

A new v2/summary endpoint replaces the v1/budgets endpoint.

This endpoint significantly refactors the response and aligns with the recently released v2 Budgets feature.

View v2 Summary Endpoint Docs
View v2 Summary Object Docs