openapi: 3.0.2
info:
title: Lunch Money API - v2
description: |-
Welcome to the Lunch Money v2 API reference. This is the **v2.11.1** spec. It includes previews of the proposed `/crypto` and `/balance_history` endpoints. Only the mock service works with these endpoints.
The most recent stable version of the API is v2.9.4 and is available at:
`https://api.lunchmoney.dev/v2`
------------------------------------------------------------------------------------------------
### Introduction
The API is available at `https://api.lunchmoney.dev/v2`. Get your access token from the [Lunch Money developers page](https://my.lunchmoney.app/developers).
The v2 API is in open alpha and is still subject to change. Use the mock server or a test budget when getting started.
**Static Mock Server**
Explore the API without an access token or risk to real data. Select **"Static Mock v2 Lunch Money API Server"** from the Server dropdown, then set your Bearer token to any string with 11 or more characters.
**Client Libraries & SDKs**
An official TypeScript SDK is available on [NPM](https://www.npmjs.com/package/@lunch-money/v2-api-spec) and [GitHub](https://github.com/lunch-money/lunch-money-js-v2). For Python or other languages, see [lunchmoney-clients](https://github.com/juftin/lunchmoney-clients) or generate a client from this OpenAPI spec.
**Migrating from v1**
The v2 API is not backwards compatible with v1. See the [Migration Guide](https://alpha.lunchmoney.dev/v2/migration-guide) for details.
**Useful links**
- [Developer Portal](https://alpha.lunchmoney.dev/v2/introduction)
- [Getting Started Guide](https://alpha.lunchmoney.dev/v2/getting-started)
- [v2 API Overview](https://alpha.lunchmoney.dev/v2/overview)
- [Version History](https://alpha.lunchmoney.dev/v2/version-history)
- [Migration Guide](https://alpha.lunchmoney.dev/v2/migration-guide)
- [Rate Limits](https://alpha.lunchmoney.dev/v2/rate-limits)
termsOfService: https://lunchmoney.dev/#current-status
contact:
email: devsupport@lunchmoney.app
license:
name: Apache 2.0
url: http://www.apache.org/licenses/LICENSE-2.0.html
version: 2.11.1
servers:
- url: https://api.lunchmoney.dev/v2
description: v2 Lunch Money API Server - changes will affect real data!
# - url: https://mock.lunchmoney.dev/v2
- url: https://lm-v2-api-next-a7fabcab8e9a.herokuapp.com/v2/
description: Static mock version of the v2 Lunch Money API Server
tags:
- name: me
description: View details and settings for the current user and account.
Use [/me/account/settings](#tag/me/GET/me/account/settings) and [/me/user/settings](#tag/me/GET/me/user/settings) for account- and user-level preferences. - name: categories description: Work with categories externalDocs: description: Learn more about categories url: https://support.lunchmoney.app/setup/categories - name: manual_accounts description: Work with manually managed accounts (formerly called assets) externalDocs: description: Learn more about manual accounts url: https://support.lunchmoney.app/setup/linked-accounts#how-are-manually-managed-account-balances-updated - name: plaid_accounts description: Work with accounts synced through Plaid externalDocs: description: Learn more about synced accounts url: https://support.lunchmoney.app/setup/linked-accounts#how-often-should-i-expect-new-transactions-to-get-imported - name: crypto-manual description: Work with manually managed crypto assets externalDocs: description: Learn more about crypto assets url: https://support.lunchmoney.app/setup/crypto - name: crypto-synced description: Read and refresh synced crypto assets and balances. Creating and managing connections with synced crypto providers is done exclusively in the Lunch Money web app. externalDocs: description: Learn more about crypto assets url: https://support.lunchmoney.app/setup/crypto - name: balance_history description: View and update historical account balances. Balance history is what drives the [Net Worth](https://my.lunchmoney.app/net-worth) views in the Lunch Money app. Balance history is generated for each account's balance on the first day of each month and can be edited in the Lunch Money app or via the API. - name: recurring_items description: Work with recurring items externalDocs: url: https://support.lunchmoney.app/finances/recurring-items - name: tags description: Work with tags externalDocs: description: Learn more about tags url: https://support.lunchmoney.app/setup/tags - name: transactions description: Work with transactions externalDocs: description: Learn more about transactions url: https://support.lunchmoney.app/finances/transactions - name: transactions (bulk) description: Perform bulk actions on transactions externalDocs: description: Learn more about transactions url: https://support.lunchmoney.app/finances/transactions - name: transactions (group) description: Group or ungroup transactions externalDocs: description: Learn more about transactions url: https://support.lunchmoney.app/finances/transactions - name: transactions (split) description: Split or unsplit transactions externalDocs: description: Learn more about transactions url: https://support.lunchmoney.app/finances/transactions - name: transactions (files) description: Manage files attached to transactions externalDocs: description: Learn more about transactions url: https://support.lunchmoney.app/finances/transactions - name: budgets description: View settings and modify budget amounts.
Use [/budgets/settings](#tag/budgets/GET/budgets/settings) to view budget period settings.
Use the [/summary](#tag/summary) endpoint to view the budget details performance. externalDocs: description: Learn more about budgets url: https://support.lunchmoney.app/finances/budgets - name: summary description: View a summary of the user's budget components: schemas: userObject: type: object title: user object (returned by /me) additionalProperties: false properties: name: type: string description: The user's name email: type: string description: The user's email id: type: integer format: int32 description: Unique ID for the user account_id: type: integer format: int64 description: Unique ID for the current budgeting account budget_name: type: string description: Name of the current budgeting account.
Also available as `display_name` on [/me/account/settings](#tag/me/GET/me/account/settings), which is the preferred endpoint for reading and updating account settings. primary_currency: description: Primary currency for the current budgeting account.
Also available on [/me/account/settings](#tag/me/GET/me/account/settings),
which is the preferred endpoint for reading and updating account
settings.
allOf:
- $ref: "#/components/schemas/currencyEnum"
api_key_label:
type: string
nullable: true
description: Label assigned by the user to the API key being used.
Returns null if no label is set
required:
- name
- email
- id
- account_id
- budget_name
- primary_currency
- api_key_label
categoryObject:
type: object
title: category object
additionalProperties: false
properties:
id:
type: integer
format: int32
nullable: false
description: System defined unique ID for the category
name:
type: string
nullable: false
description: Name of the category
minLength: 1
maxLength: 100
description:
type: string
nullable: true
description: Category description, or `null` if none is set
maxLength: 200
is_income:
type: boolean
nullable: false
description: 'If `true`, transactions in this category are treated
as income. (See [Category
Properties](https://support.lunchmoney.app/setup/categories/category-properties)
for details)'
exclude_from_budget:
type: boolean
nullable: false
description: 'If `true`, transactions in this category are
excluded from the budget. (See [Category
Properties](https://support.lunchmoney.app/setup/categories/category-properties)
for details)'
exclude_from_totals:
type: boolean
nullable: false
description: 'If `true`, transactions in this category are
excluded from totals. (See [Category
Properties](https://support.lunchmoney.app/setup/categories/category-properties)
for details)'
updated_at:
type: string
format: date-time
nullable: false
description: Date and time the category was last updated (in the
ISO 8601 extended format).
created_at:
type: string
format: date-time
nullable: false
description: Date and time of when the category was created (ISO
8601 extended format).
group_id:
type: integer
format: int64
nullable: true
description: ID of the category group this category belongs to, or
`null` if it does not belong to a group, or is itself a group.
is_group:
type: boolean
description: If `true`, this category is created as a category
group
children:
type: array
items:
$ref: "#/components/schemas/childCategoryObject"
description: For category groups, contains details about the
categories in the group. These objects are similar to Category
Objects but the `is_group` property will always be `false`, and
there will be no `children` attribute.
archived:
type: boolean
description: If true, the category is archived and hidden in
relevant areas of the Lunch Money app.
archived_at:
type: string
format: date-time
nullable: true
description: Date and time the category was last archived ( ISO
8601 extended format).
order:
type: integer
nullable: true
default: null
description: "Position of the category on the categories page in
the Lunch Money app. For grouped categories, the order is
relative to others in the same group.
Categories with `order: null` are shown alphabetically before ordered categories"
collapsed:
type: boolean
nullable: false
default: false
description: If `true`, the category appears collapsed in the
Lunch Money app
required:
- id
- name
- description
- is_income
- exclude_from_budget
- exclude_from_totals
- updated_at
- created_at
- group_id
- is_group
- archived
- archived_at
- order
- collapsed
# The childCategoryObject is a categoryObject without a
# `children` attribute. This ensures that only non-group categories
# are added to a category group
childCategoryObject:
type: object
x-internal: true # Don't display in schemas section of docs
additionalProperties: false
properties:
id:
type: integer
format: int32
nullable: false
description: System defined unique ID for the category
name:
type: string
nullable: false
description: The name of the category
minLength: 1
maxLength: 100
description:
type: string
nullable: true
description: Category description, or `null` if none is set
maxLength: 200
is_income:
type: boolean
nullable: false
description: If true, transactions in this category are treated as
income. (Inherited from the Category Group).
exclude_from_budget:
type: boolean
nullable: false
description: If true, transactions in this category are excluded from
the budget. (Inherited from Category Group).
exclude_from_totals:
type: boolean
nullable: false
description: If true, transactions in this category are excluded from
totals. (Inherited from Category Group).
updated_at:
type: string
format: date-time
nullable: false
description: Date and time the category was last updated (ISO 8601
extended format).
created_at:
type: string
format: date-time
nullable: false
description: Date and time the category was created (ISO 8601 extended
format).
group_id:
type: integer
format: int64
nullable: true
description: ID of the category group this category belongs to, or
`null` if it does not belong to a group, or is itself a group.
is_group:
type: boolean
enum:
- false
description: Always false for categories that belong to a category
group
archived:
type: boolean
description: If true, the category is archived and hidden in relevant
areas of the Lunch Money app.
archived_at:
type: string
format: date-time
nullable: true
description: Date and time the category was last archived ( ISO 8601
extended format).
order:
type: integer
nullable: true
description: Position of the category on the categories page in the
Lunch Money app. For grouped categories, the order is relative to
the others in the same group.
collapsed:
type: boolean
nullable: false
description: Always `false` for a child category. Child categories
cannot be collapsed.
required:
- id
- name
- description
- is_income
- exclude_from_budget
- exclude_from_totals
- updated_at
- created_at
- group_id
- is_group
- archived
- archived_at
- order
- collapsed
# The request object for POST /categories
# Prevent user from submitting any system created fields in a POST request
createCategoryRequestObject:
type: object
additionalProperties: false
x-internal: true
properties:
name:
type: string
nullable: false
description: >-
Name of the new category. Must be between 1 and 100 characters.
The name must not match the name of any existing categories or category
groups.
minLength: 1
maxLength: 100
description:
type: string
nullable: true
default: null
description: Description of the category. Maximum length is 200
characters.
minLength: 0 # Allow empty strings
maxLength: 200
is_income:
type: boolean
nullable: false
default: false
description: If `true`, transactions in this category are treated as
income. (See [Category
Properties](https://support.lunchmoney.app/setup/categories/category-properties)
for details)
exclude_from_budget:
type: boolean
nullable: false
default: false
description: If `true`, transactions in this category are excluded
from the budget. (See [Category
Properties](https://support.lunchmoney.app/setup/categories/category-properties)
for details)
exclude_from_totals:
type: boolean
nullable: false
default: false
description: If `true`, transactions in this category are excluded
from totals. (See [Category
Properties](https://support.lunchmoney.app/setup/categories/category-properties)
for details)
is_group:
type: boolean
nullable: false
default: false
description: If `true`, this category will be created as a category
group.
group_id:
type: integer
format: int64
nullable: true
default: null
description: If set to the ID of an existing category group, the new
category will be added to that group. Cannot be used if `is_group`
is true.
archived:
type: boolean
default: false
description: If `true`, the category is archived and in relevant areas
of the Lunch Money app.
children:
type: array
nullable: false
description: List of categories to include in the new category group.
This field should only be set if `is_group` is also set to true.
You may provide existing category objects, existing category IDs, or
names for new categories to add to the group. Categories or IDs must
already exist and cannot be category groups. Categories that already
belong to another group will be moved. If strings are provided, they
will be used as names for new categories added to the group. The
request will fail if any provided name already exists.
You may
mix category objects, IDs, and new category names in the same
request.
items:
oneOf:
- type: integer
description: "ID of an existing category."
- type: string
description: "Name of a new child category to be created."
maxLength: 100
- $ref: "#/components/schemas/categoryObject"
order:
type: integer
nullable: true
description: Position of the category on the categories page in the
Lunch Money app. For grouped categories, the order is relative to
other categories in the same group.
While this property can be
set via the API, it is usually managed by the user in the Lunch
Money app.
collapsed:
type: boolean
nullable: true
description: If `true`, the category group appears collapsed in the
Lunch Money app. Can only be set to `true` for category
groups.
While this property can be set via the API, it is usually
managed by the user in the Lunch Money app.
required:
- name
# Request object for a PUT /categories/:id request
# Tolerates a request object that includes system created fields from a
# previous GET request, but these are essentially ignored
updateCategoryRequestObject:
type: object
x-internal: true
additionalProperties: false
properties:
name:
type: string
nullable: false
description: If set, updates the category name. Must be between 1 and
100 characters.
minLength: 1
maxLength: 100
x-updatable: true
description:
type: string
nullable: true
description: If set, updates the category description. Must not exceed
200 characters.
minLength: 0 # Allow empty strings
maxLength: 200
x-updatable: true
is_income:
type: boolean
nullable: false
description: If set, determines whether transactions in this category
are treated as income. (See [Category
Properties](https://support.lunchmoney.app/setup/categories/category-properties)
for details)
x-updatable: true
exclude_from_budget:
type: boolean
nullable: false
description: If set, determines whether transactions in this category
are excluded from budgets. (See [Category
Properties](https://support.lunchmoney.app/setup/categories/category-properties)
for details)
x-updatable: true
exclude_from_totals:
type: boolean
nullable: false
description: If set, determines whether transactions in this category
are excluded from totals. (See [Category
Properties](https://support.lunchmoney.app/setup/categories/category-properties)
for details)
x-updatable: true
archived:
type: boolean
description: If set, determines whether this category is archived.
x-updatable: true
group_id:
type: integer
format: int64
nullable: true
description: If set to the ID of an existing category group, and this
category is not itself a category group, this category will be
assigned to that group.
x-updatable: true
is_group:
type: boolean
nullable: true
default: false
description: This property is tolerated but cannot be changed. This
API cannot be used to convert a category into a category group or
vice versa.
children:
type: array
nullable: false
description: List of existing category objects, existing category IDs,
or names of new categories to add to the category group. This
attribute should only be set when modifying an existing category
group.
Categories or IDs must already exist and must not already
belong to a category group. Categories that already belong to
another category group will be moved. If strings are specified, they
will be used as names for new categories added to the group. The
request will fail if any provided name matches an existing category
name.
You may mix full category objects, IDs, and new category
names in the same request.
x-updatable: true
items:
oneOf:
- type: integer
description: "ID of an existing category."
- type: string
description: "Name of a new child category to be created."
maxLength: 100
- $ref: "#/components/schemas/categoryObject"
order:
type: integer
nullable: true
description: Position of the category on the categories page in the
Lunch Money app. For categories within a category group, the order
is relative to the other categories in the group.
While this
property can be set via the API, it is generally managed by the user
in the Lunch Money app.
x-updatable: true
collapsed:
type: boolean
nullable: true
description: If `true`, the category is collapsed in the Lunch Money
app.
While this property can be set via the API it is generally
set by the user in the Lunch Money app.
x-updatable: true
id:
type: integer
format: int64
description: System defined unique identifier for the category.
Ignored if set.
x-updatable: false
archived_at:
type: string
format: date-time
nullable: true
description: System set date and time of when the category was last
archived (in the ISO 8601 extended format). Provide an ISO 8601
extended datetime or `null` to clear it.
x-updatable: true
updated_at:
type: string
format: date-time
nullable: false
description: System set date and time of when the category was last
updated (in the ISO 8601 extended format). Ignored if set.
x-updatable: false
created_at:
type: string
format: date-time
nullable: false
description: System set date and time of when the category was created
(in the ISO 8601 extended format). Ignored if set.
x-updatable: false
# The response object for a DELETE /category request with dependencies
deleteCategoryResponseWithDependencies:
type: object
x-internal: true
additionalProperties: false
properties:
category_name:
type: string
description: The name of the category
dependents:
type: object
properties:
budget:
type: integer
description: The number of budgets depending on the category
category_rules:
type: integer
description: The number of category rules depending on the
category
transactions:
type: integer
description: The number of transactions depending on the category
children:
type: integer
description: The number of child categories in the category group
recurring:
type: integer
description: The number of recurring transactions depending on the
category
plaid_cats:
type: integer
description: The number of auto created categories based on Plaid
categories
required:
- budget
- category_rules
- transactions
- children
- recurring
- plaid_cats
required:
- category_name
- dependents
# Manual crypto balance object
cryptoManualObject:
type: object
title: manual crypto object
additionalProperties: false
properties:
id:
type: integer
format: int32
description: System defined unique ID for the manual crypto balance
name:
type: string
minLength: 1
maxLength: 45
description: User-defined name for the crypto asset
display_name:
type: string
nullable: true
description: Optional display name for the crypto asset. If `null`,
clients may derive a display name from `institution_name` + `name`.
institution_name:
type: string
nullable: true
minLength: 1
maxLength: 50
description: Institution or wallet provider display name
balance:
type: string
pattern: ^-?\d+(\.\d{1,18})?$
description: Current balance in numeric format to 18 decimal places
symbol:
type: string
minLength: 1
maxLength: 25
description: Cryptocurrency symbol
coingecko_id:
type: string
nullable: true
minLength: 1
maxLength: 100
description: CoinGecko identifier associated with this balance
to_base:
type: number
nullable: true
description: Balance converted to the user's primary currency. May be null if no conversion was available.
balance_as_of:
type: string
format: date-time
nullable: true
description: Date/time the manual balance record was last updated in
ISO 8601 extended format. This is currently based on the manual
crypto record's updated_at timestamp.
exchange_rate_as_of:
type: string
format: date-time
nullable: true
description: Date/time the exchange rate used to calculate to_base was
last updated in ISO 8601 extended format. Null when no exchange rate was
used or no conversion was available.
created_by_name:
type: string
nullable: true
description: Name of the user who created the crypto asset
created_at:
type: string
format: date-time
description: Date/time the crypto asset was created in ISO 8601
extended format
updated_at:
type: string
format: date-time
description: Date/time the crypto asset was last updated in ISO 8601
extended format
required:
- id
- name
- display_name
- institution_name
- balance
- symbol
- coingecko_id
- to_base
- balance_as_of
- exchange_rate_as_of
- created_by_name
- created_at
- updated_at
# Synced per-symbol balance nested under a synced crypto account
cryptoSyncedBalance:
type: object
title: synced crypto balance object
additionalProperties: false
properties:
name:
type: string
minLength: 1
maxLength: 45
description: The asset name for this balance, typically the uppercased currency symbol (e.g. ETH).
display_name:
type: string
nullable: true
description: Optional display name for the synced crypto asset as set by the user. If `null`,
clients may derive a display name from syncedCryptoAccount's `provider` + `name`.
balance:
type: string
pattern: ^-?\d+(\.\d{1,18})?$
description: Current balance in numeric format to 18 decimal places
symbol:
type: string
minLength: 1
maxLength: 25
description: Symbol of the currency held in the synced account
coingecko_id:
type: string
nullable: true
minLength: 1
maxLength: 100
description: CoinGecko identifier associated with this balance
to_base:
type: number
nullable: true
description: Balance converted to the user's primary currency. May be null if no conversion was available.
balance_as_of:
type: string
format: date-time
nullable: true
description: Date/time the balance was last updated in ISO 8601
extended format.
exchange_rate_as_of:
type: string
format: date-time
nullable: true
description: Date/time the exchange rate used to calculate to_base was
last updated in ISO 8601 extended format. Null when no exchange rate was
used or no conversion was available.
updated_at:
type: string
format: date-time
description: Date/time the crypto asset was last updated in ISO 8601
extended format
required:
- name
- display_name
- balance
- symbol
- coingecko_id
- to_base
- balance_as_of
- exchange_rate_as_of
- updated_at
syncedCryptoAccount:
type: object
title: synced crypto account
additionalProperties: false
properties:
id:
type: integer
format: int32
description: System defined unique ID for the synced crypto connection
provider:
type: string
description: Provider used for the synced crypto connection
enum:
- kraken
- coinbase
- ethereum
status:
type: string
description: Status of the synced crypto account. If not `active`,
see the [Knowledge
Base](https://support.lunchmoney.app/setup/crypto#why-is-my-synced-crypto-account-showing-not-supported)
for details.
enum:
- active
- unsupported
- relink
- initializing
created_by_name:
type: string
nullable: true
description: Name of the user who created the crypto connection
created_at:
type: string
format: date-time
description: Date/time the synced crypto connection was created in ISO
8601 extended format
updated_at:
type: string
format: date-time
description: Date/time the synced crypto connection was last updated
in ISO 8601 extended format
last_import:
type: string
format: date-time
nullable: true
description: System defined timestamp in ISO 8601 extended format of
the last successful import.
display_name:
type: string
nullable: true
description: Optional display name for the synced crypto connection
balances:
type: array
items:
$ref: "#/components/schemas/cryptoSyncedBalance"
description: Balances currently held in the synced crypto connection
required:
- id
- provider
- status
- created_by_name
- created_at
- updated_at
- display_name
- balances
# Response object returned by GET /crypto/manual
cryptoManualListResponseObject:
type: object
x-internal: true
additionalProperties: false
properties:
crypto_manual:
type: array
items:
$ref: "#/components/schemas/cryptoManualObject"
required:
- crypto_manual
# Response object returned by GET /crypto/synced
cryptoSyncedListResponseObject:
type: object
x-internal: true
additionalProperties: false
properties:
crypto_synced:
type: array
items:
$ref: "#/components/schemas/syncedCryptoAccount"
required:
- crypto_synced
cryptoCurrencyObject:
type: object
x-internal: true
additionalProperties: false
properties:
id:
type: integer
format: int32
description: System-defined unique identifier for this
cryptocurrency in Lunch Money.
coingecko_id:
type: string
minLength: 1
maxLength: 100
description: System-defined CoinGecko identifier used to fetch
the USD-based prices for this cryptocurrency.
symbol:
type: string
minLength: 1
maxLength: 25
description: Lowercase currency symbol that must be used as
`symbol` when creating a manual crypto balance.
full_name:
type: string
minLength: 1
maxLength: 200
description: Human-readable name of the cryptocurrency.
required:
- id
- coingecko_id
- symbol
- full_name
# Response object returned by GET /cryptocurrencies
cryptoCurrencyResponseObject:
type: object
x-internal: true
additionalProperties: false
properties:
cryptocurrencies:
type: array
description: List of cryptocurrencies currently supported for manual
tracking.
items:
$ref: "#/components/schemas/cryptoCurrencyObject"
required:
- cryptocurrencies
createCryptocurrencyRequestObject:
type: object
additionalProperties: false
x-internal: true
properties:
coingecko_url:
type: string
minLength: 1
maxLength: 200
description: CoinGecko coin-page URL in the form
`https://www.coingecko.com/{locale}/coins/{id}`
example: https://www.coingecko.com/en/coins/cardano
required:
- coingecko_url
# The object that may be submitted to POST /crypto/manual
createCryptoManualRequestObject:
type: object
additionalProperties: false
x-internal: true
properties:
name:
type: string
minLength: 1
maxLength: 45
description: User-defined name for the manual crypto asset
example: Cold Wallet BTC
display_name:
type: string
minLength: 1
maxLength: 45
description: Optional display name for the manual crypto asset. If
omitted, clients may derive one from `institution_name` + `name`.
example: Cold Storage
institution_name:
type: string
minLength: 1
maxLength: 50
description: Optional institution or wallet provider display name
example: Ledger
balance:
oneOf:
- type: number
format: double
- type: string
pattern: ^-?\d+(\.\d{1,18})?$
description: Numeric value of the balance, up to 18 decimal places
example: "0.523400000000000000"
symbol:
type: string
minLength: 1
maxLength: 25
description: Cryptocurrency symbol to track. Must match the `symbol`
of one of the supported cryptocurrencies returned by `GET
/cryptocurrencies`.
example: btc
required:
- name
- balance
- symbol
# The object that may be submitted to PUT /crypto/manual/{id}
updateCryptoManualRequestObject:
type: object
x-internal: true
additionalProperties: false
properties:
id:
type: integer
format: int32
description: System defined unique ID for the manual crypto asset.
Ignored if set
x-updatable: false
name:
type: string
nullable: true
minLength: 1
maxLength: 45
description: If set, the new name of the manual crypto asset
x-updatable: true
display_name:
type: string
nullable: true
minLength: 1
maxLength: 45
description: If set, the new display name for the manual crypto asset
x-updatable: true
institution_name:
type: string
nullable: true
minLength: 1
maxLength: 50
description: If set, the new institution or wallet provider display
name
x-updatable: true
balance:
oneOf:
- type: number
format: double
- type: string
pattern: ^-?\d+(\.\d{1,18})?$
description: If set, the new balance value up to 18 decimal places
example: "1.050000000000000000"
x-updatable: true
symbol:
type: string
minLength: 1
maxLength: 25
description: Existing cryptocurrency symbol. Ignored if set.
x-updatable: false
coingecko_id:
type: string
nullable: true
minLength: 1
maxLength: 100
description: System-defined CoinGecko identifier for this symbol.
Ignored if set.
x-updatable: false
to_base:
type: number
description: System defined balance converted to the user's primary
currency. Ignored if set
x-updatable: false
balance_as_of:
type: string
format: date-time
nullable: true
description: System defined date/time the manual balance record was
last updated in ISO 8601 extended format. Ignored if set
x-updatable: false
exchange_rate_as_of:
type: string
format: date-time
nullable: true
description: System defined date/time the exchange rate used to
calculate to_base was observed in ISO 8601 extended format. Ignored
if set
x-updatable: false
created_by_name:
type: string
nullable: true
description: System defined name of the user who created the crypto
asset. Ignored if set
x-updatable: false
created_at:
type: string
format: date-time
description: System defined date/time the crypto asset was created in
ISO 8601 extended format. Ignored if set
x-updatable: false
updated_at:
type: string
format: date-time
description: System defined date/time the crypto asset was last
updated in ISO 8601 extended format. Ignored if set
x-updatable: false
description: Update a manual crypto balance. System-defined properties are
accepted when resubmitting a `GET /crypto/manual/{id}` response body.
# The object containing information about a manual account
manualAccountObject:
type: object
title: manual account object
additionalProperties: false
description: An object containing information about a manual account
properties:
id:
type: integer
format: int32
description: The unique identifier of this account
name:
type: string
description: Name of the account
minLength: 1
maxLength: 45
institution_name:
type: string
nullable: true
minLength: 1
maxLength: 50
description: Name of institution holding the account
display_name:
type: string
nullable: true
description: Optional display name for the account as set by the user
or derived from the `institution_name` and `name` if not explicitly
set.
type:
description: Primary type of the account
allOf:
- $ref: "#/components/schemas/accountTypeEnum"
subtype:
type: string
nullable: true
description: Optional account subtype. Examples include
-
retirement - checking - savings - prepaid credit card
minLength: 1
maxLength: 100
balance:
type: string
pattern: ^-?\d+(\.\d{1,4})?$
description: Current balance of the account in numeric format to 4
decimal places
currency:
type: string
minLength: 3
maxLength: 3
description: Three-letter lowercase currency code of the account
balance
to_base:
type: number
description: The balance converted to the user's primary currency
balance_as_of:
type: string
format: date-time
description: Date balance was last updated in ISO 8601 extended
format, can be in date or date-time format
status:
type: string
description: The status of the account
enum:
- active
- closed
closed_on:
type: string
format: date
nullable: true
description: The date this account was closed in YYYY-MM-DD format.
Will be null if the account has not been marked as closed.
external_id:
type: string
nullable: true
minLength: 0
maxLength: 75
description: An optional external_id that may be set or updated via
the API
custom_metadata:
type: object
nullable: true
description: User defined JSON data that can be set or cleared via the
API
additionalProperties: true
exclude_from_transactions:
type: boolean
default: false
description: If true, this account will not show up as an option for
assignment when creating transactions manually
created_by_name:
type: string
description: The name of the user who created the account
created_at:
type: string
format: date-time
description: Date/time the account was created in ISO 8601 extended
format
updated_at:
type: string
format: date-time
description: Date/time the account was last updated in ISO 8601
extended format
required:
- id
- name
- type
- subtype
- display_name
- balance
- currency
- to_base
- balance_as_of
- closed_on
- institution_name
- external_id
- exclude_from_transactions
- created_by_name
- created_at
- updated_at
- status
# The object that may be submitted to POST /manual_accounts
createManualAccountRequestObject:
type: object
additionalProperties: false
x-internal: true
properties:
name:
type: string
description: Name of the manual account
minLength: 1
maxLength: 45
example: My Savings Account
institution_name:
type: string
example: Bank of the West
description: Name of institution holding the manual account
minLength: 1
maxLength: 50
display_name:
type: string
description: Display name of the manual account as set by user or
derived from the `institution_name` and `name` if not explicitly
set.
This must be unique for the budgeting account.
example: Savings
type:
description: The type of manual account
allOf:
- $ref: "#/components/schemas/accountTypeEnum"
subtype:
type: string
description: An optional manual account subtype. Examples include
- retirement - checking - savings - prepaid credit card
minLength: 1
maxLength: 100
example: prepaid credit card
balance:
oneOf:
- type: number
format: double
- type: string
pattern: ^-?\d+(\.\d{1,4})?$
example: "195.50"
description: Numeric value of the current balance, up to four decimal
places, of the account as a number or string. Do not include any
special characters aside from a decimal point.
balance_as_of:
type: string
oneOf:
- format: date-time
- format: date
example: "2024-09-15"
description: Date/time the balance of the manual account was last
updated in ISO 8601 extended format
currency:
description: Three-letter lowercase currency code of the transaction
in ISO 4217 format
allOf:
- $ref: "#/components/schemas/currencyEnum"
status:
type: string
description: The status of the account
enum:
- active
- closed
default: active
closed_on:
oneOf:
- type: string
format: date
- type: string
format: date-time
nullable: true
example: "2024-10-01"
description: The date this manual account was closed in YYYY-MM-DD
format. If set, `status` must also be set to `closed`.
external_id:
type: string
nullable: true
minLength: 0
maxLength: 75
description: An optional user-defined ID for the manual account
custom_metadata:
type: object
nullable: true
description: An optional JSON object that includes additional data
related to this account. This must be a valid JSON object and, when
stringified, must not exceed 4096 characters.
additionalProperties: true
exclude_from_transactions:
type: boolean
description: If `true`, transactions may not be assigned to this
manual account
default: false
required:
- name
- type
- balance
# The object that may be submitted to PUT /manual_accounts/:id
updateManualAccountRequestObject:
type: object
x-internal: true
additionalProperties: false
properties:
id:
type: integer
format: int32
description: System defined unique identifier of this account. Ignored
if set
x-updatable: false
name:
type: string
description: If set, the new name of the manual account
minLength: 1
maxLength: 45
x-updatable: true
institution_name:
type: string
nullable: true
description: If set, the name of the institution holding the account
minLength: 1
maxLength: 50
x-updatable: true
display_name:
type: string
nullable: true
description: If set, the new display name for the manual account.
This must be unique for the user.
x-updatable: true
type:
description: If set, the new type of the manual account
x-updatable: true
allOf:
- $ref: "#/components/schemas/accountTypeEnum"
subtype:
type: string
nullable: true
description: If set, an optional account subtype. Set to `null` to clear it.
Examples include
- retirement - checking - savings - prepaid credit card
minLength: 1
maxLength: 100
example: prepaid credit card
x-updatable: true
balance:
oneOf:
- type: number
format: double
- type: string
pattern: ^-?\d+(\.\d{1,4})?$
example: "195.50"
description: Numeric value of the current balance, up to four decimal
places, of the manual account as a number or string. Do not include
any special characters aside from a decimal point.
x-updatable: true
currency:
description: If set, the new three-letter lowercase currency code of
the manual account balance.
x-updatable: true
allOf:
- $ref: "#/components/schemas/currencyEnum"
balance_as_of:
type: string
oneOf:
- format: date-time
- format: date
description: "If set, updates the `balance_as_of` value. May be
provided as a date in YYYY-MM-DD format or as a date-time string in
ISO 8601 extended format. This property is ignored unless `balance`
is also set. If `balance` is set and this property is not set, the
current time is used."
x-updatable: true
status:
type: string
description: If set, updates the status of the manual account. If set
to `closed`, `closed_on` will be set to the current date unless it
is also set.
enum:
- active
- closed
x-updatable: true
closed_on:
nullable: true
oneOf:
- type: string
format: date
- type: string
format: date-time
description: If set, the date this manual account was closed in
YYYY-MM-DD format. If updating an account that is not already
closed, `status` must also be set to `closed`.
x-updatable: true
external_id:
type: string
nullable: true
minLength: 0
maxLength: 75
description: An optional user-defined ID for the manual account
x-updatable: true
custom_metadata:
type: object
nullable: true
description: An optional JSON object that includes additional data
related to this account. This must be a valid JSON object and, when
stringified, must not exceed 4096 characters.
additionalProperties: true
x-updatable: true
exclude_from_transactions:
type: boolean
description: If set, transactions may not be assigned to this manual
account
x-updatable: true
to_base:
type: number
description: System defined balance converted to the user's primary
currency. Ignored if set. Use `balance` to update the balance in the
account
x-updatable: false
created_at:
type: string
format: date-time
description: System defined date/time the account was created in ISO
8601 extended format. Ignored if set.
x-updatable: false
updated_at:
type: string
format: date-time
description: System defined date/time the account was last updated in
ISO 8601 extended format. Ignored if set.
x-updatable: false
created_by_name:
type: string
description: System defined name of the user who created the account.
Ignored if set
x-updatable: false
# The object containing information about a Plaid account
plaidAccountObject:
type: object
title: plaid account object
additionalProperties: false
description: An object containing information about an account synced via
Plaid
properties:
id:
type: integer
format: int32
description: The unique identifier of this account
plaid_item_id:
type: string
nullable: true
minLength: 0
maxLength: 255
description: The unique identifier of the Plaid connection that this
account belongs to. Accounts with the same plaid_item_id usually
belong to the same institution.
date_linked:
type: string
format: date
description: Date account was first linked in ISO 8601 format
linked_by_name:
type: string
nullable: false
description: The name of the user who linked the account
name:
type: string
description: Name of the account. This field is set by Plaid and
cannot be altered.
display_name:
type: string
nullable: true
description: Optional display name for the account set by the user. If
not set, it will return a concatenated string of institution and
account name.
type:
type: string
description: Primary type of the account, such as `credit`,
`depository`, etc. This field is set by Plaid and cannot be altered.
subtype:
type: string
description: Optional account subtype. This field is set by Plaid and
cannot be altered.
mask:
type: string
description: Mask (last 3 to 4 digits of account) of account. This
field is set by Plaid and cannot be altered.
institution_name:
type: string
description: Name of institution holding the account. This field is
set by Plaid and cannot be altered.
status:
type: string
description: "Denotes the current status of the account within Lunch
Money. Must be one of
- active: Account is actively syncing transactions and/or balance
- inactive: Account marked inactive from user. Transaction imports and balance updates will not occur for this account.
- closed: Account is marked as closed
- deactivated: Account is marked deactivated during setup. The user must click `Add/Remove Accounts From This Bank` and manually re-select this account to activate it.'
- not found: Account was once linked but can no longer be found with Plaid.
- not supported: Account is not supported by Plaid.
- relink: Account (and others with the same connection) need to be relinked with Plaid.
- syncing: Account is awaiting the first import of transactions.
- revoked: Account connection has been revoked by Plaid and syncing is no longer possible. A new connection needs to be set up again.
- error: Account (and others with the same connection) is in error with Plaid and requires intervention to re-activate it.
"
enum:
- active
- inactive
- closed
- deactivated
- not found
- not supported
- relink
- syncing
- revoked
- error
allow_transaction_modifications:
type: boolean
description: If `false`, transactions imported for this synced account
can have their properties (such as amount and account) be modified
by the user. This option is managed in the Lunch Money app.
limit:
type: number
nullable: true
description: Optional credit limit of the account. This field is set
by Plaid and cannot be altered
balance:
type: string
description: Current balance of the account in numeric format to 4
decimal places. This field is set by Plaid and cannot be altered.
currency:
type: string
minLength: 3
maxLength: 3
description: Three-letter lowercase currency code of the account
balance
to_base:
type: number
description: The account balance converted to the user's primary
currency
balance_last_update:
type: string
format: date-time
nullable: true
description: Date balance was last updated in ISO 8601 extended
format. This field is set by Plaid and cannot be altered.
import_start_date:
type: string
format: date
nullable: true
description: Date of earliest date allowed for importing transactions.
Transactions earlier than this date are not imported.
last_import:
type: string
format: date-time
nullable: true
description: Timestamp in ISO 8601 extended format of the last time
Lunch Money imported new data from Plaid for this account.
last_fetch:
type: string
format: date-time
nullable: true
description: Timestamp in ISO 8601 extended format of the last
successful request from Lunch Money for updated data or timestamps
from Plaid in ISO 8601 extended format (not necessarily date of last
successful import)
plaid_last_successful_update:
type: string
format: date-time
nullable: true
description: Timestamp in ISO 8601 extended format of the last time
Plaid successfully connected with institution for new transaction
updates, regardless of whether any new data was available in the
update.
required:
- id
- plaid_item_id
- date_linked
- linked_by_name
- name
- display_name
- type
- subtype
- mask
- institution_name
- status
- allow_transaction_modifications
- limit
- balance
- currency
- to_base
- balance_last_update
- import_start_date
- last_import
- last_fetch
- plaid_last_successful_update
balanceHistorySourceManual:
type: object
description: Source information for a manual account balance history entry.
additionalProperties: false
x-internal: true
properties:
type:
type: string
enum: [manual]
description: Identifies this entry as belonging to a manually-managed account.
manual_account_id:
type: integer
format: int32
description: ID of the manual account associated with this entry.
required:
- type
- manual_account_id
balanceHistorySourcePlaid:
type: object
description: Source information for a Plaid-synced account balance history entry.
additionalProperties: false
x-internal: true
properties:
type:
type: string
enum: [plaid]
description: Identifies this entry as belonging to a Plaid-synced account.
plaid_account_id:
type: integer
format: int32
description: ID of the Plaid account associated with this entry.
required:
- type
- plaid_account_id
balanceHistorySourceCryptoManual:
type: object
description: Source information for a manually-tracked cryptocurrency balance history entry.
additionalProperties: false
x-internal: true
properties:
type:
type: string
enum: [crypto_manual]
description: Identifies this entry as belonging to a manually-tracked crypto account.
crypto_manual_id:
type: integer
format: int32
description: ID of the manual crypto account associated with this entry.
symbol:
type: string
nullable: true
minLength: 1
maxLength: 25
description: Crypto symbol associated with the manual crypto account, when available.
required:
- type
- crypto_manual_id
balanceHistorySourceCryptoSynced:
type: object
x-internal: true
description: Source information for a synced cryptocurrency balance history entry.
additionalProperties: false
properties:
type:
type: string
enum: [crypto_synced]
description: Identifies this entry as belonging to a synced crypto connection.
crypto_synced_id:
type: integer
format: int32
description: ID of the synced crypto connection associated with this entry.
symbol:
type: string
minLength: 1
maxLength: 25
description: Crypto symbol (e.g. `eth`, `btc`) identifying the specific currency within the synced account.
required:
- type
- crypto_synced_id
- symbol
balanceHistorySourceDeleted:
type: object
x-internal: true
description: >
Source information for a balance history entry whose account has since been deleted.
Historical balances are preserved when a user chooses to keep history on account deletion.
This object contains details that can be used to display the deleted account in the UI.
The `deleted_account_id` can be passed to `PUT /v2/balance_history/deleted/{account_id}/details`
to update the archived source metadata.
additionalProperties: false
properties:
type:
type: string
enum: [deleted]
description: Identifies this entry as belonging to an account that has since been deleted.
deleted_account_id:
type: integer
format: int32
description: Identifier for the deleted account history source
name:
type: string
nullable: true
description: Archived account `name` for the deleted account source
institution_name:
type: string
nullable: true
description: Archived `institution_name` for the deleted account source
display_name:
type: string
nullable: true
description: Archived `display_name` of the deleted account
account_type:
type: string
nullable: true
description: Archived `type` of the deleted account source
subtype:
type: string
nullable: true
description: Archived `subtype`` of the deleted account source
mask:
type: string
nullable: true
description: Archived account `mask` for a deleted plaid account source
symbol:
type: string
nullable: true
minLength: 1
maxLength: 25
description: Archived `symbol` for a deleted crypto account source
required:
- type
- deleted_account_id
- name
- institution_name
- display_name
- account_type
- subtype
- mask
- symbol
balanceHistoryAccountObject:
type: object
title: balance history for an account object
additionalProperties: false
description: Historical balance entries grouped under a single account source.
properties:
source:
description: >
Identifies the account this balance entry belongs to. The shape varies by
`source.type`. Use `source.type` to determine which account id field is present.
oneOf:
- $ref: "#/components/schemas/balanceHistorySourceManual"
- $ref: "#/components/schemas/balanceHistorySourcePlaid"
- $ref: "#/components/schemas/balanceHistorySourceCryptoManual"
- $ref: "#/components/schemas/balanceHistorySourceCryptoSynced"
- $ref: "#/components/schemas/balanceHistorySourceDeleted"
discriminator:
propertyName: type
mapping:
manual: "#/components/schemas/balanceHistorySourceManual"
plaid: "#/components/schemas/balanceHistorySourcePlaid"
crypto_manual: "#/components/schemas/balanceHistorySourceCryptoManual"
crypto_synced: "#/components/schemas/balanceHistorySourceCryptoSynced"
deleted: "#/components/schemas/balanceHistorySourceDeleted"
balances:
type: array
description: >
Monthly balance history entries for the source account. On GET responses,
this includes all entries in the requested range. On PUT upsert responses,
this includes only the entries modified by that request.
items:
$ref: "#/components/schemas/balanceHistoryObject"
required:
- source
- balances
balanceHistoryObject:
type: object
title: balance history entry object
additionalProperties: false
x-internal: true
description: A historical balance entry for a single account on a single date.
properties:
id:
type: integer
format: int32
description: Unique identifier of this historical balance entry.
date:
type: string
format: date
description: Date of this historical balance entry in YYYY-MM-DD format. This is always the first day of a month.
balance:
type: string
pattern: ^-?\d+(\.\d{1,4})?$
description: Historical balance stored for this entry, as a numeric string with up to four decimal places. Trailing zeros and decimal places are not guaranteed in responses. For manual and Plaid accounts this is in the account currency. For crypto accounts this is in the user's primary currency.
currency:
allOf:
- $ref: "#/components/schemas/currencyEnum"
description: Currency of the stored `balance`. For crypto entries this is the user's primary currency.
to_base:
type: number
format: double
description: Historical balance converted to the user's primary currency. When the entry currency is the user's primary currency, this is the numeric value of `balance`.
crypto_balance:
type: string
nullable: true
pattern: ^-?\d+(\.\d{1,18})?$
description: Crypto quantity stored for this balance entry, when available. This may be present for crypto or deleted-account entries and is `null` otherwise.
required:
- id
- date
- balance
- currency
- to_base
- crypto_balance
balanceHistoryListResponseObject:
type: object
additionalProperties: false
x-internal: true
properties:
balance_history:
type: array
items:
$ref: "#/components/schemas/balanceHistoryAccountObject"
required:
- balance_history
balanceHistoryUpdateItemObject:
type: object
x-internal: true
additionalProperties: false
properties:
id:
type: integer
format: int32
description: System-defined balance history entry id. Ignored if set.
x-updatable: false
date:
type: string
format: date
description: Month to update, in YYYY-MM-DD format. This must be the first day of a month and must be in a past month.
balance:
oneOf:
- type: number
format: double
- type: string
pattern: ^-?\d+(\.\d{1,4})?$
description: Numeric value of the historical balance, up to four decimal places, as a number or string. For manual and Plaid accounts this is typically in the account currency. For crypto and deleted accounts this is typically in the user's primary currency. Do not include any special characters aside from a decimal point.
symbol:
type: string
nullable: true
minLength: 1
maxLength: 25
description: Optional for crypto balances, but if set it must match the account's symbol.
Tolerated for deleted-account balances. Do not provide this for manual or Plaid balances.
If provided when using the synced crypto path-based endpoint, this must match the symbol in the path.
x-updatable: true
crypto_balance:
type: string
nullable: true
pattern: ^-?\d+(\.\d{1,18})?$
description: Optional crypto quantity for crypto_manual, crypto_synced, and deleted balances. Do not provide this for manual or Plaid balances.
x-updatable: true
currency:
allOf:
- $ref: "#/components/schemas/currencyEnum"
description: Optional currency for this balance entry. If omitted, it defaults to the account currency for manual/Plaid accounts, or the user's primary currency for crypto/deleted accounts.
x-updatable: true
to_base:
type: number
format: double
description: System-defined historical balance converted to the user's primary currency. Ignored if set. Use `balance` to update the stored historical balance.
x-updatable: false
required:
- date
- balance
upsertBalanceHistoryRequestObject:
type: object
x-internal: true
additionalProperties: false
properties:
balances:
type: array
minItems: 1
description: One or more monthly balance history entries to upsert
items:
$ref: "#/components/schemas/balanceHistoryUpdateItemObject"
required:
- balances
updateBalanceHistoryDetailsRequestObject:
type: object
x-internal: true
additionalProperties: false
minProperties: 1
properties:
name:
type: string
nullable: true
description: New archived account name for the deleted account source.
institution_name:
type: string
nullable: true
description: New archived institution name for the deleted account source.
display_name:
type: string
nullable: true
description: New display name for the deleted account source.
account_type:
type: string
nullable: true
description: New archived account type for the deleted account source.
subtype:
type: string
nullable: true
description: New archived subtype for the deleted account source.
mask:
type: string
nullable: true
description: New archived account mask for the deleted account source.
updateBalanceHistoryDetailsResponseObject:
type: object
x-internal: true
additionalProperties: false
properties:
name:
type: string
nullable: true
institution_name:
type: string
nullable: true
display_name:
type: string
nullable: true
account_type:
type: string
nullable: true
subtype:
type: string
nullable: true
mask:
type: string
nullable: true
required:
- name
- institution_name
- display_name
- account_type
- subtype
- mask
# The object containing information about a recurring item
recurringObject:
type: object
title: recurring item object
properties:
id:
type: integer
format: int32
description: The unique identifier of this recurring item
description:
type: string
nullable: true
description: An optional description of this recurring item.
status:
type: string
description: The status of this recurring item. `suggested` recurring
items are generated by Lunch Money, but only `reviewed` recurring
items will be applied to matching transactions.
enum:
- suggested
- reviewed
transaction_criteria:
type: object
description: The set of properties used to identify matching
transactions.
properties:
start_date:
type: string
format: date
nullable: true
description: The beginning of the date range for matching
transactions. If `null`, any transactions before end_date may be
considered.
end_date:
type: string
format: date
nullable: true
description: The end of the date range for matching transactions.
If `null`, any transactions after start_date may be considered.
granularity:
type: string
description: The unit of time used to define the cadence of the
recurring item.
enum:
- day
- week
- month
- year
quantity:
type: integer
description: The number of granularity units between each
recurrence.
anchor_date:
type: string
format: date
nullable: false
description: The date used in conjunction with the `quantity` and
`granularity` properties to calculate expected occurrences of
recurring transactions.
payee:
type: string
nullable: true
description: If set, specifies the original transaction payee name
that triggered this recurring item's creation.
amount:
type: string
pattern: ^-?\d+(\.\d{1,4})?$
description: The expected amount for a transaction that will match
this recurring item. For recurring items that have a flexible
amount this is the average of the specified min and max amounts.
to_base:
type: number
description: The amount converted to the user's primary currency
currency:
type: string
nullable: false
description: Three-letter lowercase currency code of the recurring
item.
plaid_account_id:
type: integer
format: int64
nullable: true
description: The Plaid account ID associated with the recurring
item, if any.
manual_account_id:
type: integer
format: int64
nullable: true
description: The manual account ID associated with the recurring
item, if any.
required:
- start_date
- end_date
- granularity
- quantity
- anchor_date
- payee
- amount
- to_base
- currency
- plaid_account_id
- manual_account_id
overrides:
type: object
description: The values that will be applied to matching transactions.
properties:
payee:
type: string
nullable: false
description: If present, the payee name that will be displayed for
any matching transactions.
notes:
type: string
nullable: false
description: If present, the notes that will be displayed for any
matching transactions.
category_id:
type: integer
nullable: false
description: If present, the ID of the category that matching
transactions will be assigned to.
matches:
type: object
nullable: true
description: Details on expected, found and missing transactions for
the specified range. This will be `null` for recurring items with a
`status` of `suggested`.
properties:
request_start_date:
type: string
format: date
description: The beginning of the date range that this request
used to find matching transactions.
request_end_date:
type: string
format: date
description: The beginning of the date range that this request
used to find matching transactions.
expected_occurrence_dates:
type: array
items:
type: string
format: date
description: A list of dates within the specified range where a
recurring transactions is expected.
found_transactions:
type: array
description: A list with the dates and IDs of matching
transactions.
items:
type: object
properties:
date:
type: string
format: date
description: The date for a matching transaction within the
specified range.
transaction_id:
type: integer
description: The ID of a matching transaction within the
specified range.
missing_transaction_dates:
type: array
items:
type: string
format: date
description: A list of dates within the range of where a recurring
transaction was expected but none was found.
created_by:
type: integer
nullable: false
description: The ID of the user who created the recurring item.
created_at:
type: string
format: date-time
nullable: false
description: Date/time the recurring item was created in ISO 8601
extended format.
updated_at:
type: string
format: date-time
nullable: false
description: Date/time the recurring item was updated in ISO 8601
extended format.
source:
type: string
description: >
This can be one of four values:
- `manual`: User created this recurring item manually from the
Recurring Items page
- `transaction`: User created this by converting a transaction from
the Transactions page
- `system`: Recurring item was created by the system on transaction
import
- `null`: Some older recurring items may not have a source.
enum:
- manual
- transaction
- system
required:
- id
- description
- status
- transaction_criteria
- overrides
- matches
- created_by
- created_at
- updated_at
- source
# The object containing information about a tag
tagObject:
type: object
title: tag object
additionalProperties: false
properties:
id:
type: integer
format: int32
description: Unique identifier for the tag.
name:
type: string
description: Name of the tag.
description:
type: string
nullable: true
description: Description of the tag.
text_color:
type: string
nullable: true
description: The text color of the tag.
background_color:
type: string
nullable: true
description: The background color of the tag.
updated_at:
type: string
format: date-time
nullable: false
description: The date and time of when the tag was last updated (in
the ISO 8601 extended format).
created_at:
type: string
format: date-time
nullable: false
description: The date and time of when the tag was created (in the ISO
8601 extended format).
archived:
type: boolean
description: If `true`, the tag will not show up when creating or
updating transactions in the Lunch Money app.
archived_at:
type: string
format: date-time
nullable: true
description: The date and time of when the tag was last archived or
`null` if not archived
required:
- id
- name
- description
- text_color
- background_color
- created_at
- updated_at
- archived
- archived_at
# The object that may be submitted to POST /tags
createTagRequestObject:
type: object
additionalProperties: false
x-internal: true
properties:
name:
type: string
nullable: false
description: |-
The name of the new tag. Must be between 1 and 100 characters.
Must not match the name of any existing tags.
minLength: 1
maxLength: 100
description:
type: string
nullable: true
default: null
description: The description of the tag. Must not exceed 200
characters.
maxLength: 200
text_color:
type: string
nullable: true
description: The text color of the tag.
background_color:
type: string
nullable: true
description: The background color of the tag.
archived:
type: boolean
default: false
description: If `true`, the tag is archived and not displayed in
relevant areas of the Lunch Money app.
required:
- name
# The object that may be submitted to PUT /tags/:id
updateTagRequestObject:
type: object
x-internal: true
additionalProperties: false
properties:
name:
type: string
nullable: false
description: If set, the new name of the tag. Must be between 1 and
100. characters.
minLength: 1
maxLength: 100
x-updatable: true
description:
type: string
nullable: true
description: If set, the new description of the tag. Must not exceed
200. characters.
maxLength: 200
x-updatable: true
text_color:
type: string
nullable: true
description: The text color of the tag.
x-updatable: true
background_color:
type: string
nullable: true
description: The background color of the tag.
x-updatable: true
archived:
type: boolean
description: If set, determines whether this tag is archived.
x-updatable: true
id:
type: integer
format: int32
description: System-defined unique identifier for the tag. Ignored if
set.
x-updatable: false
updated_at:
type: string
format: date-time
nullable: false
description: System-set time the tag was last updated. Ignored if set
x-updatable: false
created_at:
type: string
format: date-time
nullable: false
description: System-set time the tag was created. Ignored if set.
x-updatable: false
archived_at:
type: string
format: date-time
nullable: true
description: If set, updates the archived timestamp for the tag.
Provide an ISO 8601 extended datetime or `null` to clear it.
x-updatable: true
# The object returned when a DELETE /tag/:id request
# has an id for a tag that has dependencies
deleteTagResponseWithDependencies:
type: object
x-internal: true
additionalProperties: false
properties:
tag_name:
type: string
description: The name of the tag
dependents:
type: object
properties:
rules:
type: integer
description: The number of rules depending on the tag
transactions:
type: integer
description: The number of transactions with the tag
required:
- rules
- transactions
required:
- tag_name
- dependents
# The primary object that represents a transaction
transactionObject:
type: object
title: transaction object
additionalProperties: false
properties:
id:
type: integer
format: int64
description: System-created unique identifier for the transaction
date:
type: string
format: date
description: Transaction date in ISO 8601 format
amount:
type: string
description: Amount of the transaction in numeric format to 4 decimal
places. Positive values indicate a debit transaction, negative
values indicate a credit transaction.
currency:
description: Three-letter lowercase currency code of the transaction
in ISO 4217 format.
allOf:
- $ref: "#/components/schemas/currencyEnum"
to_base:
type: number
format: double
description: The amount converted to the user's primary currency. If
the multi-currency feature is not being used, to_base and amount
will be the same. Positive values indicate a debit transaction,
negative values indicate a credit transaction.
recurring_id:
type: integer
format: int32
nullable: true
description: The unique identifier of the associated recurring item
that this transaction matched.
payee:
type: string
description: |
Name of payee set by the user, the financial institution, or by
a matched recurring item. This will match the value
displayed in payee field on the transactions page in the Lunch Money app.
original_name:
type: string
nullable: true
description: Original payee name from the source (financial
institution, CSV, etc.). For Plaid transactions, this is the raw
name before normalization. For manual/API transactions, this
typically matches `payee`. May be null for older transactions.
category_id:
type: integer
format: int32
nullable: true
description: Unique identifier of associated category set by the user
or by a matched recurring_item.
Category details can be obtained
by passing the value of this property to the [Get A Single
Category](../operations/getCategoryById) API
plaid_account_id:
type: integer
format: int32
nullable: true
description: The unique identifier of the plaid account associated
with this transaction. This will always be null if this transaction
is associated with a manual account or if this transaction has no
associated account and appears as a "Cash Transaction" in the Lunch
Money app.
manual_account_id:
type: integer
format: int32
nullable: true
description: The unique identifier of the manual account associated
with this transaction. This will always be null if this transaction
is associated with a synced account or if this transaction has no
associated account and appears as a "Cash Transaction" in the Lunch
Money app.
external_id:
type: string
nullable: true
description: A user-defined external ID associated with the transaction.
For transactions belonging to manual accounts, the
external ID must be unique for each transaction associated with the account.
minLength: 0
maxLength: 75
tag_ids:
type: array
nullable: false
description: A list of tag_ids for the tags associated with this
transaction. If the transaction has no tags this will be an empty
list.
Tag details can be obtained by passing the value of this
attribute as the `ids` query parameter to the [List
Tags](../operations/getTags) API
items:
type: integer
format: int32
notes:
type: string
nullable: true
description: |
Any transaction notes set by the user or by
a matched recurring item. This will match the value
displayed in notes field on the transactions page in the Lunch Money app.
status:
type: string
# description: >
# Status of the transaction. Will be one of the following values:
# x-enumDescriptions:
# reviewed: User has reviewed the transaction, or it was automatically marked as reviewed due to reviewed recurring_item logic
# unreviewed: User has not reviewed the transaction and it does not match any reviewed recurring_items.
# delete_pending: The synced account deleted this transaction after it was updated by the user. Requires manual intervention.
description: >
Status of the transaction:
- `reviewed`: User has reviewed the transaction, or it was
automatically marked as reviewed due to reviewed recurring_item
logic
- `unreviewed`: User has not reviewed the transaction and it does
not match any reviewed recurring_items. Note that any transactions
where `is_pending` is true will be returned with a status of unreviewed.
- `delete_pending`: The synced account deleted this transaction
after it was updated by the user. Requires manual intervention.
enum:
- reviewed
- unreviewed
- delete_pending
is_pending:
type: boolean
description: Denotes if the transaction is pending (not posted).
Applies only to transactions in synced accounts and will always be
false for transactions associated with manual accounts.
created_at:
type: string
format: date-time
description: The date and time of when the transaction was created (in
the ISO 8601 extended format).
updated_at:
type: string
format: date-time
description: The date and time of when the transaction was last
updated (in the ISO 8601 extended format).
is_split_parent:
type: boolean
description: If `true`, this transaction has been split into two or
more other transactions. By default, parent transactions are not
returned in call to `GET /transactions` but they can be queried
directly by their ID.
split_parent_id:
type: integer
format: int64
nullable: true
description: A transaction ID if this is a split transaction. Denotes
the transaction ID of the original, or parent, transaction. Is null
if this is not a split transaction
is_group_parent:
type: boolean
description: "`true` if this transaction represents a group of
transactions. If so, amount and currency represent the totalled
amount of transactions bearing this transaction's id as their
group_parent_id. Amount is calculated based on the user's primary
currency."
group_parent_id:
type: integer
format: int64
nullable: true
description: If set, this transaction is part of a group. Denotes the
ID of the grouped transaction that it is included in. By default,
the transactions that were grouped are not returned in a call to
`GET /transactions` but they can be queried directly by calling the
`GET /transactions/group/{id}`, where the id passed is associated
with a transaction where the `is_group_parent` attribute is true.
children:
type: array
nullable: false
items:
$ref: "#/components/schemas/childTransactionObject"
description: Exists only for transactions which are the parent of a
split transaction or for transaction groups. It will not exist in
the response unless the `include_children` query parameter is set to
`true`.
For parents of split transactions, it contains a list of
the associated transactions that it was split into. For transaction
groups, it contains the transactions that were grouped together.
Examine the `is_split_parent` and `is_group_parent` properties to
determine which of these it is.
plaid_metadata:
type: object
nullable: true
description: If requested, the transaction's plaid_metadata that came
when this transaction was obtained. This will be a JSON object, but
the schema is variable. This is only present when the
`include_metadata` query parameter is set to true.
custom_metadata:
type: object
nullable: true
description: If requested, the transaction's custom_metadata that was
included when the transaction was inserted via the API. This will be
a JSON object, but the schema is variable. This is only present when
the `include_metadata` query parameter is set to true.
files:
type: array
nullable: false
description: A list of objects that describe any attachments to the
transaction. This is only present when the `include_files` query
parameter is set to true.
items:
$ref: "#/components/schemas/transactionAttachmentObject"
source:
type: string
nullable: true
description: >
Source of the transaction:
- `api`: Transaction was added by a call to the [POST
/transactions](../operations/createTransaction) API
- `csv`: Transaction was added via a CSV Import
- `manual`: Transaction was created via the "Add to Cash" button on
the Transactions page
- `merge`: Transactions were originally in an account that was
merged into another account
- `plaid`: Transaction came from a Financial Institution synced via
Plaid
- `recurring`: Transaction was created from the Recurring page
- `rule`: Transaction was created by a rule to split a transaction
- `split`: Transaction was created by splitting another
transaction
- `user`: This is a legacy value and is replaced by either csv or
manual
enum:
- api
- csv
- manual
- merge
- plaid
- recurring
- rule
- split
- user
required:
- id
- date
- amount
- currency
- to_base
- recurring_id
- payee
- category_id
- notes
- status
- is_pending
- created_at
- updated_at
- split_parent_id
- is_group_parent
- group_parent_id
- manual_account_id
- plaid_account_id
- tag_ids
- source
- external_id
# The childTransactionObject is basically a transactionObject that has no
# `children` attribute which should not be present on grouped or split
# transactions.
childTransactionObject:
type: object
x-internal: true
additionalProperties: false
properties:
id:
type: integer
format: int64
description: System-created unique identifier for the transaction
date:
type: string
format: date
description: Transaction date in ISO 8601 format
amount:
type: string
description: Amount of the transaction in numeric format to 4 decimal
places. Positive values indicate a debit transaction, negative
values indicate a credit transaction.
currency:
description: Three-letter lowercase currency code of the transaction
in ISO 4217 format
allOf:
- $ref: "#/components/schemas/currencyEnum"
to_base:
type: number
format: double
description: The amount converted to the user's primary currency. If
the transaction currency is the same as the user's primary currency,
to_base and amount will be the same. Positive values indicate a
debit transaction, negative values indicate a credit transaction.
recurring_id:
type: integer
format: int32
nullable: true
description: The unique identifier of the associated recurring item
that this transaction matched.
payee:
type: string
description: |
Name of payee set by the user, the financial institution, or by
a matched recurring item. This will match the value
displayed in payee field on the transactions page in the Lunch Money app.
original_name:
type: string
nullable: true
description: Original payee name from the source (financial
institution, CSV, etc.). For Plaid transactions, this is the raw
name before normalization. For manual/API transactions, this
typically matches `payee`. May be null for older transactions.
category_id:
type: integer
format: int32
nullable: true
description: Unique identifier of associated category set by the user
or by a matched recurring item.
Category details can be obtained
by passing the value of this property to the [Get A Single
Category](../operations/getCategoryById) API
notes:
type: string
nullable: true
description: |
Any transaction notes set by the user or by
a matched recurring item. This will match the value
displayed in notes field on the transactions page in the Lunch Money app.
status:
type: string
description: >
Status of the transaction. Will be one of the following values:
x-enumDescriptions:
reviewed: User has reviewed the transaction, or it was automatically marked as reviewed due to reviewed recurring item logic
unreviewed: User has not reviewed the transaction and it does not match any reviewed recurring_items. Note that any transactions where `is_pending` is true will be returned with a status of unreviewed.
delete_pending: The synced account deleted this transaction after it was updated by the user. Requires manual intervention.
# description: >
# Status of the transaction:
# - `reviewed`: User has reviewed the transaction, or it was
# automatically marked as reviewed due to reviewed recurring_item
# logic
# - `unreviewed`: User has not reviewed the transaction and it does
# not match any reviewed recurring_items.
# - `delete_pending`: The synced account deleted this transaction
# after it was updated by the user. Requires manual intervention.
enum:
- reviewed
- unreviewed
- delete_pending
is_pending:
type: boolean
description: Denotes if the transaction is pending (not posted).
Applies only to transactions in synced accounts and will always be
false for transactions associated with manual accounts.
created_at:
type: string
format: date-time
description: The date and time of when the transaction was created (in
the ISO 8601 extended format).
updated_at:
type: string
format: date-time
description: The date and time of when the transaction was last
updated (in the ISO 8601 extended format).
is_split_parent:
type: boolean
description: If `true`, this transaction has been split into two or
more other transactions. By default, parent transactions are not
returned in call to `GET /transactions` but they can be queried
directly by their ID.
split_parent_id:
type: integer
format: int64
nullable: true
description: A transaction ID if this is a split transaction. Denotes
the transaction ID of the original, or parent, transaction. Is null
if this is not a split transaction
is_group_parent:
type: boolean
description: True if this transaction represents a group of
transactions. If so, amount and currency represent the totalled
amount of transactions bearing this transaction's id as their
group_parent_id. Amount is calculated based on the user's primary
currency.
group_parent_id:
type: integer
format: int64
nullable: true
description: If set, this transaction is part of a group. Denotes the
ID of the grouped transaction that it is included in. By default,
the transactions that were grouped are not returned in a call to
`GET /transactions` but they can be queried directly by calling the
`GET /transactions/group/{id}`, where the id passed is associated
with a transaction where the `is_group_parent` attribute is true.
manual_account_id:
type: integer
format: int32
nullable: true
description: The unique identifier of the manual account associated
with this transaction. This will always be null if this transaction
is associated with a synced account or if this transaction has no
associated account and appears as a "Cash Transaction" in the Lunch
Money app.
plaid_account_id:
type: integer
format: int32
nullable: true
description: The unique identifier of the plaid account associated
with this transaction. This will always be null if this transaction
is associated with a manual account or if this transaction has no
associated account and appears as a "Cash Transaction" in the Lunch
Money app.
tag_ids:
type: array
nullable: false
description: A list of tag_ids for the tags associated with this
transaction. If the transaction has no tags this will be an empty
list.
Tag details can be obtained by passing the value of this
attribute as the `ids` query parameter to the [List
Tags](../operations/getTags) API
items:
type: integer
format: int32
source:
type: string
nullable: true
description: >
Source of the transaction:
- `api`: Transaction was added by a call to the [POST
/transactions](../operations/createTransaction) API
- `csv`: Transaction was added via a CSV Import
- `manual`: Transaction was created via the "Add to Cash" button on
the Transactions page
- `merge`: Transactions were originally in an account that was
merged into another account
- `plaid`: Transaction came from a Financial Institution synced via
Plaid
- `recurring`: Transaction was created from the Recurring page
- `rule`: Transaction was created by a rule to split a transaction
- `split`: This is a transaction created by splitting another
transaction
- `user`: This is a legacy value and is replaced by either csv or
manual
enum:
- api
- csv
- manual
- merge
- plaid
- recurring
- rule
- split
- user
external_id:
type: string
nullable: true
description: A user-defined external ID associated with the transaction.
For transactions belonging to manual accounts, the
external ID must be unique for each transaction associated with the account.
minLength: 0
maxLength: 75
plaid_metadata:
type: object
nullable: true
description: If requested, the transaction's plaid_metadata that came
when this transaction was obtained. This will be a JSON object, but
the schema is variable. This will only be present for transactions
associated with a plaid account.
custom_metadata:
type: object
nullable: true
description: If requested, the transaction's custom_metadata that was
included when the transaction was inserted via the API. This will be
a JSON object, but the schema is variable.
files:
type: array
nullable: false
description: A list of objects that describe any attachments to the
transaction
items:
$ref: "#/components/schemas/transactionAttachmentObject"
required:
- id
- date
- amount
- currency
- to_base
- recurring_id
- payee
- category_id
- notes
- status
- is_pending
- created_at
- updated_at
- split_parent_id
- is_group_parent
- group_parent_id
- manual_account_id
- plaid_account_id
- tag_ids
- source
- external_id
# The request object for a POST /transactions request
# It contains only user settable properties.
insertTransactionObject:
type: object
x-internal: true
additionalProperties: false
properties:
date:
type: string
format: date
description: Transaction date in ISO 8601 format
amount:
oneOf:
- type: number
format: double
- type: string
pattern: ^-?\d+(\.\d{1,4})?$
description: Numeric value of the amount without a currency symbol.
For example, $4.25 should be provided as 4.25. May be a string or a
number in double format. Positive values indicate a debit
transaction, negative values indicate a credit transaction.
currency:
description: Three-letter lowercase currency code of the transaction
in ISO 4217 format. Must match one of the [supported
currencies](https://lm-v2-api-next-a7fabcab8e9a.herokuapp.com/v2/currencies). If not set
defaults to the user account's primary currency.
allOf:
- $ref: "#/components/schemas/currencyEnum"
payee:
type: string
description: Name of payee for the transaction
original_name:
type: string
nullable: true
description: Original payee name. If not provided, defaults to `payee`
value.
category_id:
type: integer
format: int32
nullable: true
description: The ID of the category associated with the transaction.
If set, the category ID must exist for the user's account and it
cannot be a category group.
notes:
type: string
nullable: true
description: |
Any transaction notes set by the user or by
a matched recurring item. This will match the value
displayed in notes field on the transactions page in the Lunch Money app.
manual_account_id:
type: integer
format: int32
nullable: true
description: The unique identifier of the associated manual account.
If set, this must match an existing manual account id associated
with the user's account. If not set, and `plaid_account_id` is also
not set, no account is associated with the transaction and it will
appear as a "Cash Transaction" in the Lunch Money app. It is an
error if this and `plaid_account_id` are both set on the same
transaction.
plaid_account_id:
type: integer
format: int32
nullable: true
description: The unique identifier of the associated Plaid account. If
set, this must match an existing plaid account id associated with
the user's account. If not set, and `manual_account_id` is also not
set, no account is associated with the transaction and it will
appear as a "Cash Transaction" in the Lunch Money app. It is an
error if this and `manual_account_id` are both set on the same
transaction. In addition the specified plaid account must have the
"Allow Modifications To Transactions" property set (which is enabled
by default), or the insert will fail.
recurring_id:
type: integer
format: int32
nullable: true
description: Unique identifier for associated recurring item.
Recurring item must be associated with the same account.
status:
type: string
description: If set, must be either `reviewed` or `unreviewed`. If not
set, defaults to `unreviewed`.
enum:
- reviewed
- unreviewed
tag_ids:
type: array
nullable: false
description: A list of IDs for the tags associated with this
transaction. Each ID must match an existing tag associated with the
user's account. If not set, no tags will be associated with the
created transaction.
items:
type: integer
format: int32
external_id:
type: string
nullable: true
description: A user-defined external ID for the transaction. If set,
and `manual_account_id` is set, the creation of the new transaction
will fail if a transaction with this id already exists for the
specified manual account.
minLength: 0
maxLength: 75
custom_metadata:
type: object
nullable: true
description: An optional JSON object that includes additional data
related to this transaction. This must be a valid JSON object and,
when stringified, must not exceed 4096 characters. This data may be
available in the future for processing by rules.
additionalProperties: true
required:
- date
- amount
# The object that may be submitted to PUT /transactions/:id
# System set properties such as id and created_at are tolerated but ignored
updateTransactionObject:
type: object
x-internal: true
additionalProperties: false
properties:
id:
type: integer
format: int64
description: System defined unique identifier of this transaction.
Ignored if set.
x-updatable: false
date:
type: string
format: date
description: Transaction date in ISO 8601 format
x-updatable: true
amount:
oneOf:
- type: number
format: double
- type: string
pattern: ^-?\d+(\.\d{1,4})?$
description: Numeric value of the amount without a currency symbol.
For example, $4.25 should be provided as 4.25. May be a string or a
number in double format. Positive values indicate a debit
transaction, negative values indicate a credit transaction.
May
not be updated on transactions that belong to a synced account with
the "Allow Modifications to Transactions" property disabled.
x-updatable: true
currency:
description: Three-letter lowercase currency code of the transaction
in ISO 4217 format.
May not be updated on transactions that
belong to a synced account with the "Allow Modifications to
Transactions" property disabled.
x-updatable: true
allOf:
- $ref: "#/components/schemas/currencyEnum"
recurring_id:
type: integer
format: int32
nullable: true
description: The unique identifier of the associated recurring item
that this transaction matches.
x-updatable: true
payee:
type: string
description: |
The new payee for the transaction.
minLength: 0
original_name:
type: string
nullable: true
description: Original payee name. Cannot be changed. Ignored if set.
x-updatable: false
category_id:
type: integer
format: int32
nullable: true
description: Unique identifier of the category for this transaction.
Set this to null to clear the transaction's category.
x-updatable: true
notes:
type: string
nullable: true
description: >
New notes for the transaction. Set this to an empty string to clear
the existing notes.
x-updatable: true
manual_account_id:
type: integer
format: int32
nullable: true
description: The unique identifier of the manual account associated
with this transaction. Set this to null to disassociate the
transaction with an account. If set, `plaid_account_id` may not also
be set to a non null value. Moving an existing transaction to
another account will not work if the transaction belongs to a synced
account whose "Allow Modifications to Transactions" property is not
set.
x-updatable: true
plaid_account_id:
type: integer
format: int32
nullable: true
description: The unique identifier of the Plaid account associated
with this transaction. If set, `manual_account_id` may not also be
set to a non null value. Attempting to modify this on a transaction
associated with a Plaid account will not work if the account's
"Allow Modifications to Transactions" property is not set.
Similarly, this cannot be set to an id associated with this type of
locked Plaid account.
x-updatable: true
tag_ids:
type: array
nullable: false
description: A list of tag_ids for the tags associated with this
transaction. If set, this property will overwrite any existing tags.
Use `additional_tag_ids` to add tags to the existing transaction's
tags. Set this to an empty array to remove all tags from a
transaction. If set `additional_tag_ids` may not be set.
x-updatable: true
items:
type: integer
format: int32
additional_tag_ids:
type: array
nullable: false
description: A list of tag_ids for the tags associated with this
transaction. If set, the tags listed in this property will be added
to any existing transaction tags. Use `tag_ids` to overwrite or
clear transaction tags. If set, `tag_ids` may not be set.
x-updatable: true
items:
type: integer
format: int32
external_id:
type: string
nullable: true
description: A user-defined external ID for the transaction. The
update will fail if the transaction does not also have a
`manual_account_id` or if there is already an existing transaction
with the same `manual_account_id`/`external_id` combination.
minLength: 0
maxLength: 75
x-updatable: true
custom_metadata:
type: object
nullable: true
description: User defined JSON data that can be set or cleared via the
API.
x-updatable: true
status:
type: string
description: >
Status of the transaction, may be one of:
- `reviewed`: User has reviewed the transaction, or it was
automatically marked as reviewed due to reviewed recurring_item
logic
- `unreviewed`: User has not reviewed the transaction and it does
not match any reviewed recurring_items.
enum:
- reviewed
- unreviewed
x-updatable: true
to_base:
type: number
format: double
description: System defined amount of this transaction in the user's
primary currency. Ignored if set. Use `amount` to update the amount
in the transaction.
x-updatable: false
is_pending:
type: boolean
description: System defined flag set for pending transactions. Ignored
if set.
x-updatable: false
plaid_metadata:
type: object
nullable: true
description: System set metadata from a Plaid account sync. Ignored if
set.
x-updatable: false
created_at:
type: string
format: date-time
description: System defined date and time of when the transaction was
created. Ignored if set.
x-updatable: false
updated_at:
type: string
format: date-time
description: System defined date and time of when the transaction was
last updated. Ignored if set.
x-updatable: false
is_split_parent:
type: boolean
description: System defined boolean indicating if this transaction was
split. To split or unsplit a transaction use the
`/transactions/split` endpoint. Ignored if set.
x-updatable: false
children:
type: array
nullable: false
items:
$ref: "#/components/schemas/childTransactionObject"
description: An array of child transactions present when a transaction
has been split or when the transaction is a group. Split and grouped
transactions may not be modified using this API. Ignored if set.
x-updatable: false
split_parent_id:
type: integer
format: int64
nullable: true
description: A transaction ID if this is a split transaction. Split
transactions may not be modified this API. Use the
`transactions/split` endpoint instead. Ignored if set.
x-updatable: false
is_group_parent:
type: boolean
description: System defined boolean indicating if this transaction
represents a group of transactions. Grouped transactions may not be
modified with this API. Use the `transactions/group` endpoint
instead. Ignored if set.
x-updatable: false
group_parent_id:
type: integer
format: int64
nullable: true
description: A transaction group ID if this transaction is part of a
group. Grouped transactions may not be modified with this API. Use
the `transactions/group` endpoint instead. Ignored if set.
x-updatable: false
source:
type: string
nullable: true
description: |
System defined original source of the transaction. Ignored if set.
x-updatable: false
enum:
- api
- csv
- manual
- merge
- plaid
- recurring
- rule
- split
- user
# The object that may be submitted to PUT /transactions/split
splitTransactionObject:
type: object
additionalProperties: false
x-internal: true
description: The object representing a split transaction
properties:
amount:
oneOf:
- type: number
format: double
- type: string
pattern: ^-?\d+(\.\d{1,4})?$
description: Individual amount of split. Currency will inherit from
parent transaction. All amounts must sum up to parent transaction
amount.
payee:
type: string
minLength: 0
description: The payee for the child transaction. Will inherit the
original payee from the parent if not defined.
date:
type: string
format: date
description: Must be in ISO 8601 format (YYYY-MM-DD). Will inherit
from the parent if not defined.
category_id:
type: integer
format: int32
description: Unique identifier for associated category_id. Category
must already exist for the account. Will inherit category from the
parent if not defined.
tag_ids:
type: array
description: The IDs of any tags to apply to this split child
transaction. Each ID must match an existing tag.
items:
type: integer
format: int32
notes:
type: string
description: Will inherit notes from parent if not defined.
required:
- amount
# The object returned when a new transaction duplicates one that
# already exists
skippedExistingExternalIdObject:
type: object
x-internal: true
additionalProperties: false
description: The object returned when a new transaction has an external_id
that already exists
properties:
reason:
type: string
description: >
The reason the transaction was skipped, may be one of:
- `duplicate_external_id`: The transaction has the same
`manual_account_id` and `external_id` as an existing transaction
- `duplicate_payee_amount_date`: The `skip_duplicates` request body
property was set to `true` and the transaction has the same
`amount`, `payee`, and `date` as an existing
transaction associated with the same account.
enum:
- duplicate_external_id
- duplicate_payee_amount_date
request_transactions_index:
type: integer
format: int64
description: The index of the transaction in the request body's
transactions array that was skipped.
existing_transaction_id:
type: integer
format: int64
description: The id of the existing transactions that the requested
transaction duplicates.
request_transaction:
type: object
description: The requested transaction that was skipped.
allOf:
- $ref: "#/components/schemas/insertTransactionObject"
# The object returned from a successful POST /transactions request
insertTransactionsResponseObject:
type: object
x-internal: true
additionalProperties: false
description: The object returned from a successful POST /transactions
request
properties:
transactions:
description: An array of the inserted transactions.
items:
$ref: "#/components/schemas/transactionObject"
type: array
skipped_duplicates:
description: An array of the requested transactions that were
duplicates of existing transactions and were not inserted.
items:
$ref: "#/components/schemas/skippedExistingExternalIdObject"
type: array
required:
- transactions
- skipped_duplicates
# The object containing information about a file attached to a transaction
transactionAttachmentObject:
type: object
title: transaction attachment object
additionalProperties: false
# description: An object containing information about a file attached to a transaction
properties:
id:
type: integer
format: int32
description: The unique identifier of the attachment
uploaded_by:
type: integer
format: int64
description: The id of the user who uploaded the attachment
name:
type: string
description: The name of the file
type:
type: string
description: The MIME type of the file
size:
type: integer
description: The size of the file in kilobytes
notes:
type: string
nullable: true
description: Optional notes about the attachment
created_at:
type: string
format: date-time
description: The date and time when the attachment was created in ISO
8601 format
# Object that describes a budget's amount, category and start_date
budgetObject:
type: object
title: budget object
additionalProperties: false
description: "A budget object represents a budgeted amount for a specific
category and budget period. Each budget entry is tied to a specific time
period defined by its `start_date`. The budget object includes
information about the budget amount, currency, period settings, and how
future periods will be automatically calculated."
properties:
id:
type: integer
format: int64
description: System-created unique identifier for the budget entry.
category_id:
type: integer
format: int32
description: The ID of the category this budget applies to.
amount:
type: number
format: double
description: The budgeted amount for this period.
currency:
allOf:
- $ref: "#/components/schemas/currencyEnum"
description: The currency of the budgeted amount in ISO 4217 format.
start_date:
type: string
format: date
description: The start date of the budget period in ISO 8601 format
(YYYY-MM-DD). This represents the beginning of the period for which
this budget applies.
next_start_date:
type: string
format: date
readOnly: true
description: The calculated start date of the next budget period based
on the category's period settings (granularity, quantity, and
anchor_date). This is useful for determining when the next budget
period begins.
notes:
type: string
nullable: true
description: Optional notes associated with this budget period.
auto_budget_type:
type: string
readOnly: true
enum:
- nothing
- fixed
- spend
- budget
description: "The budget preset type that determines how future
periods will be automatically calculated. `nothing` means no
automatic calculation (budgets must be set manually for each
period). `fixed` uses a fixed amount for all future periods. `spend`
uses the previous period's spending amount. `budget` uses the
previous period's budgeted amount."
auto_budget_amount:
type: number
format: double
nullable: true
readOnly: true
description: "If `auto_budget_type` is `fixed`, this is the fixed
amount that will be used for future periods."
auto_budget_currency:
allOf:
- $ref: "#/components/schemas/currencyEnum"
nullable: true
readOnly: true
description: "If `auto_budget_type` is `fixed`, this is the currency
of the fixed amount."
rollover_option:
type: string
nullable: true
readOnly: true
enum:
- same category
- available funds
description: "The rollover setting for this category. `same category`
means unspent funds roll over to the next period for this category.
`available funds` means unspent funds are added to the available
funds pool. `null` means rollover is disabled."
granularity:
type: string
readOnly: true
enum:
- month
- week
- twice a month
description: "The granularity of the budget period (e.g., monthly,
weekly, twice a month). This is determined by the category's custom
budget settings or the account's default budget period settings."
quantity:
type: integer
format: int32
readOnly: true
description: "The quantity of granularity units that make up each
budget period. For example, if granularity is `week` and quantity is
`2`, each budget period is 2 weeks."
is_group:
type: boolean
readOnly: true
description: "Whether the category is a category group. Category
groups can have their own budgets that apply to all subcategories,
or subcategories can have individual budgets."
group_id:
type: integer
format: int32
nullable: true
readOnly: true
description: "If this budget is for a subcategory, this is the ID of
the parent category group. `null` if this is not a subcategory."
created_at:
type: string
format: date-time
description: The date and time when this budget entry was created (in
ISO 8601 extended format).
updated_at:
type: string
format: date-time
description: The date and time when this budget entry was last updated
(in ISO 8601 extended format).
required:
- id
- category_id
- amount
- currency
- start_date
- next_start_date
- auto_budget_type
- granularity
- quantity
- is_group
- created_at
- updated_at
# Request body for PUT /budgets (upsert)
upsertBudgetRequestObject:
x-internal: true
type: object
additionalProperties: false
properties:
start_date:
type: string
format: date
description: Start date of the budget period in ISO 8601 date format
(YYYY-MM-DD). Must be a valid budget period start for the account.
category_id:
type: integer
format: int32
description: Category ID for the budget
amount:
oneOf:
- type: number
format: double
- type: string
pattern: ^-?\d+(\.\d{1,4})?$
description: Budget amount. May be a string or a number in double
format.
currency:
allOf:
- $ref: "#/components/schemas/currencyEnum"
description: Three-letter currency code. If omitted, the primary
currency for the user's account is used.
notes:
type: string
nullable: true
description: Optional notes for the budget period
minLength: 0
maxLength: 350
required:
- start_date
- category_id
- amount
# Response body for PUT /budgets (200)
budgetUpsertResponseObject:
x-internal: true
type: object
properties:
category_id:
type: integer
format: int32
description: Category ID
start_date:
type: string
format: date
description: Start date of the budget period
amount:
type: string
description: Budget amount in the stored currency (string for
consistency with other amount fields in the API).
currency:
type: string
description: Currency code for the budget
to_base:
type: number
format: float
description: Amount converted to the user's primary currency
notes:
type: string
nullable: true
description: Notes for the budget period
# Response body for GET /budgets/settings (200)
budgetSettingsResponseObject:
type: object
title: budget settings object
additionalProperties: false
description: Budget period and display settings for the current budgeting
account.
properties:
budget_period_granularity:
type: string
enum:
- day
- week
- month
- year
- twice a month
description: Budget period granularity
budget_period_quantity:
type: integer
format: int32
description: The number of `granularity` units that make up a single
budgeting period.
budget_period_anchor_date:
type: string
format: date
description: The date from which the budgeting period is calculated.
All future (and past) periods are derived by applying `quantity` ×
`granularity` forward and backward from this date.
budget_hide_no_activity:
type: boolean
default: false
description: Display preference for hiding categories in budget view
that have no activity and no budgeted value
budget_use_last_day_of_month:
type: boolean
default: false
description: Display preference for using the last day of the month as
the period end for monthly periods
budget_income_option:
type: string
enum:
- max
- budgeted
- activity
description: Determines which income value is used as the base when
calculating available funds for a budgeting period
budget_rollover_left_to_budget:
type: boolean
default: false
description: Determines whether the remaining unallocated funds (“Left
to Budget”) at the end of a budgeting period are carried forward to
the next period
required:
- budget_hide_no_activity
- budget_period_quantity
- budget_period_granularity
- budget_period_anchor_date
- budget_use_last_day_of_month
- budget_income_option
- budget_rollover_left_to_budget
weekStartsOnEnum:
type: string
title: week starts on enum
enum:
- sunday
- monday
description: The day on which a calendar week begins.
monthYearFormatEnum:
type: string
title: month and year format enum
description: Format string for displaying month and year values
in the Lunch Money app.
enum:
- "MMMM YYYY"
- "MMM YYYY"
- "YYYY MMM"
- "MM YYYY"
- "MM-YYYY"
- "MM.YYYY"
- "MM/YYYY"
- "M YYYY"
- "M-YYYY"
- "M.YYYY"
- "M/YYYY"
- "YYYY M"
- "YYYY-M"
- "YYYY.M"
- "YYYY/M"
- "YYYY MM"
- "YYYY-MM"
- "YYYY.MM"
- "YYYY/MM"
monthDayYearFormatEnum:
type: string
title: month, day and year format enum
description: Format string for displaying full dates in the
Lunch Money app.
enum:
- "MMM D, YYYY"
- "D MMM YYYY"
- "YYYY MM DD"
- "YYYY-MM-DD"
- "YYYY.MM.DD"
- "YYYY/MM/DD"
- "YYYY M DD"
- "YYYY-M-DD"
- "YYYY.M.DD"
- "YYYY/M/DD"
- "YYYY MM D"
- "YYYY-MM-D"
- "YYYY.MM.D"
- "YYYY/MM/D"
- "YYYY M D"
- "YYYY-M-D"
- "YYYY.M.D"
- "YYYY/M/D"
- "DD MM YYYY"
- "DD-MM-YYYY"
- "DD.MM.YYYY"
- "DD/MM/YYYY"
- "DD M YYYY"
- "DD-M-YYYY"
- "DD.M.YYYY"
- "DD/M/YYYY"
- "D MM YYYY"
- "D-MM-YYYY"
- "D.MM.YYYY"
- "D/MM/YYYY"
- "D M YYYY"
- "D-M-YYYY"
- "D.M.YYYY"
- "D/M/YYYY"
- "M D YYYY"
- "M-D-YYYY"
- "M.D.YYYY"
- "M/D/YYYY"
- "MM D YYYY"
- "MM-D-YYYY"
- "MM.D.YYYY"
- "MM/D/YYYY"
- "MM DD YYYY"
- "MM-DD-YYYY"
- "MM.DD.YYYY"
- "MM/DD/YYYY"
- "M DD YYYY"
- "M-DD-YYYY"
- "M.DD.YYYY"
- "M/DD/YYYY"
monthDayFormatEnum:
type: string
title: month and day format enum
description: Format string for displaying month and day values
without a year.
enum:
- "MMM D"
- "MMM DD"
- "D MMM"
- "DD MMM"
- "MM D"
- "MM-D"
- "MM.D"
- "MM/D"
- "MM DD"
- "MM-DD"
- "MM.DD"
- "MM/DD"
- "M D"
- "M-D"
- "M.D"
- "M/D"
- "M DD"
- "M-DD"
- "M.DD"
- "M/DD"
- "D MM"
- "D-MM"
- "D.MM"
- "D/MM"
- "DD MM"
- "DD-MM"
- "DD.MM"
- "DD/MM"
- "D M"
- "D-M"
- "D.M"
- "D/M"
- "DD M"
- "DD-M"
- "DD.M"
- "DD/M"
accountSettingsObject:
type: object
title: account settings object
additionalProperties: false
description: Account-level settings for the budgeting account
associated with the authorized API token.
properties:
primary_currency:
description: Primary currency for the account.
allOf:
- $ref: "#/components/schemas/currencyEnum"
supported_currencies:
type: array
items:
$ref: "#/components/schemas/currencyEnum"
description: Currencies available when creating or editing transactions,
balances, and other amounts in the Lunch Money app.
display_name:
type: string
nullable: true
description: Display name of the budgeting account in the Lunch Money
app.
locale:
type: string
description: Locale used for formatting dates and numbers in the
Lunch Money app (for example, `en-US`). When no locale is explicitly
stored for the account, the effective locale is derived from the
`default_locale` associated with `primary_currency` in the
currencies table (for example, `usd` → `en-US`, `cad` → `en-CA`,
`gbp` → `en-GB`).
auto_create_category_rules:
type: boolean
default: true
description: If `true`, category rules are created automatically when
categorizing transactions.
auto_create_suggested_transaction_rules:
type: boolean
default: true
description: If `true`, suggested transaction rules are created
automatically.
auto_review_transaction_on_update:
type: boolean
default: true
description: If `true`, transactions are marked as reviewed when
updated.
auto_review_transaction_on_creation:
type: boolean
default: true
description: If `true`, transactions are marked as reviewed when
created.
required:
- primary_currency
- supported_currencies
- display_name
- locale
- auto_create_category_rules
- auto_create_suggested_transaction_rules
- auto_review_transaction_on_update
- auto_review_transaction_on_creation
updateAccountSettingsRequestObject:
x-internal: true
type: object
additionalProperties: false
description: Request body for updating account settings. Include at least
one property to update.
properties:
primary_currency:
allOf:
- $ref: "#/components/schemas/currencyEnum"
description: If set, updates the account's primary currency.
x-updatable: true
supported_currencies:
type: array
items:
$ref: "#/components/schemas/currencyEnum"
description: If set, replaces the list of supported currencies for the
account.
x-updatable: true
display_name:
type: string
nullable: true
description: If set, updates the display name of the budgeting account.
x-updatable: true
locale:
type: string
description: If set, updates the locale used for formatting dates and
numbers in the Lunch Money app.
x-updatable: true
auto_create_category_rules:
type: boolean
description: If set, updates whether category rules are created
automatically.
x-updatable: true
auto_create_suggested_transaction_rules:
type: boolean
description: If set, updates whether suggested transaction rules are
created automatically.
x-updatable: true
auto_review_transaction_on_update:
type: boolean
description: If set, updates whether transactions are marked as reviewed
when updated.
x-updatable: true
auto_review_transaction_on_creation:
type: boolean
description: If set, updates whether transactions are marked as reviewed
when created.
x-updatable: true
userSettingsObject:
type: object
title: user settings object
additionalProperties: false
description: User-level display and formatting preferences for the user
associated with the authorized API token.
properties:
show_debits_as_negative:
type: boolean
default: true
description: Display preference for how amounts are shown in the Lunch
Money app. When `true`, debits are shown as negative values and
credits as positive values.
This setting does **not** change amount sign conventions in API responses. Amount fields such as `amount` and `to_base` on transaction objects always use positive values for debits and negative values for credits. auto_suggest_payee: type: boolean default: true description: If `true`, payee suggestions are shown when entering transactions in the Lunch Money app. month_year_format: allOf: - $ref: "#/components/schemas/monthYearFormatEnum" default: "MMM YYYY" description: Format string used when displaying month and year values. month_day_year_format: allOf: - $ref: "#/components/schemas/monthDayYearFormatEnum" default: "MMM D, YYYY" description: Format string used when displaying full dates (month, day, and year). month_day_format: allOf: - $ref: "#/components/schemas/monthDayFormatEnum" default: "MMM D" description: Format string used when displaying month and day values without a year. show_am_pm: type: boolean default: true description: If `true`, times are displayed using a 12-hour clock with AM/PM. If `false`, times are displayed using a 24-hour clock. week_starts_on: allOf: - $ref: "#/components/schemas/weekStartsOnEnum" default: sunday description: The day on which a calendar week begins. always_display_year: type: boolean default: false description: If `true`, dates always include the year and `month_day_format` is not used. always_display_weekday: type: boolean default: true description: If `true`, weekday names are included when displaying dates. required: - show_debits_as_negative - auto_suggest_payee - month_year_format - month_day_year_format - month_day_format - show_am_pm - week_starts_on - always_display_year - always_display_weekday updateUserSettingsRequestObject: x-internal: true type: object additionalProperties: false description: Request body for updating user settings. Include at least one property to update. properties: show_debits_as_negative: type: boolean description: If set, updates the display preference for amount signs in the Lunch Money app. Does not affect amount sign conventions in API responses. x-updatable: true auto_suggest_payee: type: boolean description: If set, updates whether payee suggestions are shown. x-updatable: true month_year_format: allOf: - $ref: "#/components/schemas/monthYearFormatEnum" description: If set, updates the month and year display format. x-updatable: true month_day_year_format: allOf: - $ref: "#/components/schemas/monthDayYearFormatEnum" description: If set, updates the full date display format. x-updatable: true month_day_format: allOf: - $ref: "#/components/schemas/monthDayFormatEnum" description: If set, updates the month and day display format. x-updatable: true show_am_pm: type: boolean description: If set, updates whether times use a 12-hour (AM/PM) or 24-hour clock. x-updatable: true week_starts_on: allOf: - $ref: "#/components/schemas/weekStartsOnEnum" description: If set, updates the day on which a calendar week begins. x-updatable: true always_display_year: type: boolean description: If set, updates whether dates always include the year. x-updatable: true always_display_weekday: type: boolean description: If set, updates whether weekday names are shown when displaying dates. x-updatable: true # Summary endpoint response schemas summaryResponseObject: type: object title: summary object additionalProperties: false description: Budget summary for the requested range properties: aligned: type: boolean description: "`true` if start_date and end_date are aligned with the user's budget period setting; `false` otherwise.
When the response is not aligned, category `totals` will not include values for the `budgeted` and `available` properties, so aligned responses are usually preferred.
If unsure how to set an aligned date range, set a range of at least one month and set the `include_occurrences` parameter to `true`. Then examine the objects in the `occurrences` array for the first category to find start and end dates that will produce aligned responses. Setting `include_past_budget_dates` to `true` will add the three budget periods prior to the range in the `occurrences` array." categories: type: array items: $ref: "#/components/schemas/summaryCategoryObject" totals: $ref: "#/components/schemas/summaryTotalsObject" rollover_pool: nullable: true $ref: "#/components/schemas/summaryRolloverPoolObject" required: - aligned - categories summaryTotalsObject: x-internal: true type: object additionalProperties: false description: Total inflow and outflow for the given date range. This object is returned when the query parameter `include_totals` is set to `true`. properties: inflow: $ref: "#/components/schemas/summaryTotalsBreakdownObject" outflow: $ref: "#/components/schemas/summaryTotalsBreakdownObject" summaryTotalsBreakdownObject: type: object additionalProperties: false x-internal: true # Don't display in schemas section of docs properties: other_activity: description: Total amount, in the user's default currency, of non-recurring activity for the given date range type: number recurring_activity: description: Total amount, in the user's default currency, of recurring activity that has occurred for the given date range type: number recurring_remaining: description: Total amount, in the user's default currency, of expected recurring activity that has not yet occurred type: number recurring_expected: description: Total amount, in the user's default currency, of expected recurring activity for the given date range type: number uncategorized: description: Total amount, in the user's default currency, of non-recurring activity coming from uncategorized transactions type: number uncategorized_count: description: Number of uncategorized transactions for the given date range type: integer uncategorized_recurring: description: "Total amount, in the user's default currency, of recurring activity coming from uncategorized transactions." type: number summaryCategoryObject: x-internal: true type: object additionalProperties: false description: "List of each category's budget configuration and activity for the date range." properties: category_id: description: "ID of the category associated with the totals." type: integer totals: $ref: "#/components/schemas/summaryCategoryTotalsObject" occurrences: description: A list of objects describing the budget activity for each period within the range. This property is only present when `include_occurrences` is true.
For aligned ranges, there is one occurrence for each budget period in the range; for non-aligned, only periods fully contained in the range are included.
If
`include_past_budget_dates` is also `true`, the three budget periods
prior to the range are also included.
type: array
items:
$ref: "#/components/schemas/summaryCategoryOccurrenceObject"
required:
- category_id
- totals
summaryRolloverPoolAdjustmentObject:
type: object
additionalProperties: false
x-internal: true # Don't display in schemas section of docs
description: "The date and adjusted balance of the rollover pool at the
time of the adjustment."
properties:
in_range:
description: "`true` if this rollover pool adjustment is for a budget
period that falls within the given date range."
type: boolean
date:
description: "Date the adjustment was made."
type: string
format: date
amount:
description: "Amount of the rollover pool, in the budget's currency,
at the time of the adjustment."
type: string
currency:
description: "Currency of the rollover pool at the time of the
adjustment."
allOf:
- $ref: "#/components/schemas/currencyEnum"
to_base:
description: "Amount of the rollover pool, in the user's default
currency, at the time of the adjustment."
type: number
required:
- in_range
- date
- amount
- currency
- to_base
summaryCategoryTotalsObject:
type: object
additionalProperties: false
x-internal: true # Don't display in schemas section of docs
description: "Total activity for the given category within the given date
range when it is aligned with the budget period setting."
properties:
other_activity:
description: Total non-recurring activity, in the user's default
currency, for the category within the given date range.
The
total activity for the category is the sum of this and the
recurring_activity.
type: number
recurring_activity:
description: Total recurring activity, in the user's default currency,
for the category within the given date range.
The total activity
for the category is the sum of this and the other_activity.
type: number
budgeted:
description: "Total budgeted amount, in the user's default currency,
for the category within the given date range or null if the category
is not budgeted. This property will not be present in a non-aligned
response."
type: number
nullable: true
available:
description: "Total amount of funds available, in the user's default
currency, for the category within the given date range. This
property will not be present in a non-aligned response."
type: number
nullable: true
recurring_remaining:
description: "Total expected recurring activity, in the user's default
currency, that has not yet occurred for the category within the
given date range."
type: number
recurring_expected:
description: "Total expected recurring activity for the category
within the given date range."
type: number
required:
- other_activity
- recurring_activity
- recurring_remaining
- recurring_expected
summaryCategoryOccurrenceObject:
type: object
additionalProperties: false
x-internal: true # Don't display in schemas section of docs
description: ""
properties:
in_range:
description: "`true` if this occurrence is within the given date
range, `false` if it was included because the
`include_past_budget_periods` parameter was set to `true`."
type: boolean
start_date:
description: The start date of the budget period
type: string
format: date
end_date:
description: The end date of the budget period
type: string
format: date
other_activity:
description: Total non-recurring activity, in the user's default
currency, for the budget period. The total activity for this
category in the period is the sum of this and the
recurring_activity.
type: number
recurring_activity:
description: Total recurring activity, in the user's default currency,
for the budget period. The total activity for this category in the
budget period is the sum of this and the other_activity.
type: number
budgeted:
description: "Total budgeted amount, in the user's primary currency,
for the period, or `null` if no budget was set."
type: number
nullable: true
budgeted_amount:
description: Total budgeted amount, in the budgeted currency, for the
category within the period, or `null` if no budget was set.
type: string
nullable: true
budgeted_currency:
description: Currency of the budgeted amount
nullable: true
allOf:
- $ref: "#/components/schemas/currencyEnum"
notes:
description: "Any notes set for the budget period."
type: string
nullable: true
required:
- in_range
- start_date
- end_date
- other_activity
- recurring_activity
- budgeted
- budgeted_amount
- budgeted_currency
- notes
summaryRecurringTransactionObject:
type: object
additionalProperties: false
x-internal: true # Don't display in schemas section of docs
description: "A single transaction associated with a recurring item."
properties:
date:
type: string
format: date
category_id:
type: integer
payee:
type: string
to_base:
type: number
amount:
type: string
currency:
allOf:
- $ref: "#/components/schemas/currencyEnum"
required:
- date
- category_id
- payee
- to_base
- amount
- currency
summaryRolloverPoolObject:
type: object
additionalProperties: false
x-internal: true # Don't display in schemas section of docs
description: "Summary of the current rollover pool balance and all
previous adjustments.
Only present if the `include_rollover_pool`
query parameter is set to `true`."
properties:
budgeted_to_base:
description: "Amount of funds, in the user's default currency,
currently available to rollover."
type: number
all_adjustments:
description: List of previous adjustments to the rollover pool
type: array
items:
$ref: "#/components/schemas/summaryRolloverPoolAdjustmentObject"
required:
- budgeted_to_base
- all_adjustments
# The schema for an object returned when an error occurs
errorResponseObject:
type: object
title: error response object
description: The object returned with any 4XX error response. Each
response is guaranteed to have a `message` and at least one `error`
object.
properties:
message:
type: string
description: "High level error type, for example 'Not Found' or
'Request Validation Failure'"
errors:
description: A list of objects that describe the errors encountered
while processing the request.
If multiple errors were
encountered, the list will contain multiple objects.
Each
`error` object is guaranteed to have an `errMsg`, but it may also
contain other error-specific properties such as `code` (for example
`VALIDATION_ERROR`), or other properties that are useful to map
the error to the relevant part of the request.
type: array
items:
type: object
properties:
errMsg:
type: string
description: A message to help the developer determine the
problem with the request.
required:
- errMsg
additionalProperties: true
required:
- message
- errors
# Error response when start_date is not a valid budget period start (PUT /budgets 400)
budgetInvalidPeriodErrorObject:
x-internal: true
type: object
additionalProperties: false
description: Returned when the requested start_date is not a valid budget
period start for the account.
properties:
message:
type: string
description: Overall error message (e.g. Invalid Request)
requested_start_date:
type: string
format: date
description: The start_date value that was rejected
previous_valid_start_date:
type: string
format: date
nullable: true
description: The previous valid budget period start date before the
requested date
next_valid_start_date:
type: string
format: date
nullable: true
description: The next valid budget period start date after the
requested date
errMsg:
type: string
description: Human-readable error message
required:
- message
- requested_start_date
- errMsg
# Enums shared by multiple schemas
# Define the allowed types for a manual account
accountTypeEnum:
type: string
title: manual account type enum
enum:
- cash
- credit
- cryptocurrency
- employee compensation
- investment
- loan
- other liability
- other asset
- real estate
- vehicle
# Define the allowed types for the 3 letter currency codes
# CSpell: disable
# TODO see if we can avoid having the long doc string show up in the
# docs for the models like userObject and transactionObject that reference
# this. Ideally if users want to see the details we can offer a link instead.
currencyEnum:
type: string
title: currency enum
# Comment out this documentation until I can figure out how to override it
# in the docs that include this schema.
# description: |
# Supported Currency codes:
# - `aed`: United Arab Emirates Dirham
# - `afn`: Afghan Afghani
# - `all`: Albanian Lek
# - `amd`: Armenian Dram
# - `ang`: Netherlands Antillean Guilder
# - `aoa`: Angolan Kwanza
# - `ars`: Argentine Peso
# - `aud`: Australian Dollar
# - `awg`: Aruban Florin
# - `azn`: Azerbaijani Manat
# - `bam`: Bosnia-Herzegovina Convertible Mark
# - `bbd`: Barbadian Dollar
# - `bdt`: Bangladeshi Taka
# - `bgn`: Bulgarian Lev
# - `bhd`: Bahraini Dinar
# - `bif`: Burundian Franc
# - `bmd`: Bermudian Dollar
# - `bnd`: Brunei Dollar
# - `bob`: Bolivian Boliviano
# - `brl`: Brazilian Real
# - `bsd`: Bahamian Dollar
# - `btc`: Bitcoin
# - `btn`: Bhutanese Ngultrum
# - `bwp`: Botswanan Pula
# - `byn`: Belarusian Ruble
# - `bzd`: Belize Dollar
# - `cad`: Canadian Dollar
# - `cdf`: Congolese Franc
# - `chf`: Swiss Franc
# - `clf`: Chilean Unit of Account (UF)
# - `clp`: Chilean Peso
# - `cny`: Chinese Yuan
# - `cop`: Colombian Peso
# - `crc`: Costa Rican Colón
# - `cuc`: Cuban Convertible Peso
# - `cup`: Cuban Peso
# - `cve`: Cape Verdean Escudo
# - `czk`: Czech Republic Koruna
# - `djf`: Djiboutian Franc
# - `dkk`: Danish Krone
# - `dop`: Dominican Peso
# - `dzd`: Algerian Dinar
# - `egp`: Egyptian Pound
# - `ern`: Eritrean Nakfa
# - `etb`: Ethiopian Birr
# - `eth`: Ethereum
# - `eur`: Euro
# - `fjd`: Fijian Dollar
# - `fkp`: Falkland Islands Pound
# - `gbp`: British Pound Sterling
# - `gel`: Georgian Lari
# - `ggp`: Guernsey Pound
# - `ghs`: Ghanaian Cedi
# - `gip`: Gibraltar Pound
# - `gmd`: Gambian Dalasi
# - `gnf`: Guinean Franc
# - `gtq`: Guatemalan Quetzal
# - `gyd`: Guyanaese Dollar
# - `hkd`: Hong Kong Dollar
# - `hnl`: Honduran Lempira
# - `hrk`: Croatian Kuna
# - `htg`: Haitian Gourde
# - `huf`: Hungarian Forint
# - `idr`: Indonesian Rupiah
# - `ils`: Israeli New Sheqel
# - `imp`: Isle of Man Pound
# - `inr`: Indian Rupee
# - `iqd`: Iraqi Dinar
# - `irr`: Iranian Rial
# - `isk`: Icelandic Króna
# - `jep`: Jersey Pound
# - `jmd`: Jamaican Dollar
# - `jod`: Jordanian Dinar
# - `jpy`: Japanese Yen
# - `kes`: Kenyan Shilling
# - `kgs`: Kyrgystani Som
# - `khr`: Cambodian Riel
# - `kmf`: Comorian Franc
# - `kpw`: North Korean Won
# - `krw`: South Korean Won
# - `kwd`: Kuwaiti Dinar
# - `kyd`: Cayman Islands Dollar
# - `kzt`: Kazakhstani Tenge
# - `lak`: Laotian Kip
# - `lbp`: Lebanese Pound
# - `lkr`: Sri Lankan Rupee
# - `lrd`: Liberian Dollar
# - `lsl`: Lesotho Loti
# - `ltl`: Lithuanian Litas
# - `lvl`: Latvian Lats
# - `lyd`: Libyan Dinar
# - `mad`: Moroccan Dirham
# - `mdl`: Moldovan Leu
# - `mga`: Malagasy Ariary
# - `mkd`: Macedonian Denar
# - `mmk`: Myanma Kyat
# - `mnt`: Mongolian Tugrik
# - `mop`: Macanese Pataca
# - `mro`: Mauritanian Ouguiya
# - `mur`: Mauritian Rupee
# - `mvr`: Maldivian Rufiyaa
# - `mwk`: Malawian Kwacha
# - `mxn`: Mexican Peso
# - `myr`: Malaysian Ringgit
# - `mzn`: Mozambican Metical
# - `nad`: Namibian Dollar
# - `ngn`: Nigerian Naira
# - `nio`: Nicaraguan Córdoba
# - `nok`: Norwegian Krone
# - `npr`: Nepalese Rupee
# - `nzd`: New Zealand Dollar
# - `omr`: Omani Rial
# - `pab`: Panamanian Balboa
# - `pen`: Peruvian Nuevo Sol
# - `pgk`: Papua New Guinean Kina
# - `php`: Philippine Peso
# - `pkr`: Pakistani Rupee
# - `pln`: Polish Zloty
# - `pyg`: Paraguayan Guarani
# - `qar`: Qatari Rial
# - `ron`: Romanian Leu
# - `rsd`: Serbian Dinar
# - `rub`: Russian Ruble
# - `rwf`: Rwandan Franc
# - `sar`: Saudi Riyal
# - `sbd`: Solomon Islands Dollar
# - `scr`: Seychellois Rupee
# - `sdg`: Sudanese Pound
# - `sek`: Swedish Krona
# - `sgd`: Singapore Dollar
# - `shp`: Saint Helena Pound
# - `sll`: Sierra Leonean Leone
# - `sos`: Somali Shilling
# - `srd`: Surinamese Dollar
# - `std`: São Tomé and Príncipe Dobra
# - `svc`: Salvadoran Colón
# - `syp`: Syrian Pound
# - `szl`: Swazi Lilangeni
# - `thb`: Thai Baht
# - `tjs`: Tajikistani Somoni
# - `tmt`: Turkmenistani Manat
# - `tnd`: Tunisian Dinar
# - `top`: Tongan Paʻanga
# - `try`: Turkish Lira
# - `ttd`: Trinidad and Tobago Dollar
# - `twd`: New Taiwan Dollar
# - `tzs`: Tanzanian Shilling
# - `uah`: Ukrainian Hryvnia
# - `ugx`: Ugandan Shilling
# - `usd`: United States Dollar
# - `uyu`: Uruguayan Peso
# - `uzs`: Uzbekistan Som
# - `vef`: Venezuelan Bolívar
# - `ves`: Venezuelan Bolívar Sotiemas
# - `vnd`: Vietnamese Dong
# - `vuv`: Vanuatu Vatu
# - `wst`: Samoan Tala
# - `xaf`: CFA Franc BEAC
# - `xag`: Silver (troy ounce)
# - `xau`: Gold (troy ounce)
# - `xcd`: East Caribbean Dollar
# - `xof`: CFA Franc BCEAO
# - `xpf`: CFP Franc
# - `yer`: Yemeni Rial
# - `zar`: South African Rand
# - `zmw`: Zambian Kwacha
# - `zwl`: Zimbabwean Dollar
enum:
- aed
- afn
- all
- amd
- ang
- aoa
- ars
- aud
- awg
- azn
- bam
- bbd
- bdt
- bgn
- bhd
- bif
- bmd
- bnd
- bob
- brl
- bsd
- btc
- btn
- bwp
- byn
- bzd
- cad
- cdf
- chf
- clf
- clp
- cny
- cop
- crc
- cuc
- cup
- cve
- czk
- djf
- dkk
- dop
- dzd
- egp
- ern
- etb
- eth
- eur
- fjd
- fkp
- gbp
- gel
- ggp
- ghs
- gip
- gmd
- gnf
- gtq
- gyd
- hkd
- hnl
- hrk
- htg
- huf
- idr
- ils
- imp
- inr
- iqd
- irr
- isk
- jep
- jmd
- jod
- jpy
- kes
- kgs
- khr
- kmf
- kpw
- krw
- kwd
- kyd
- kzt
- lak
- lbp
- lkr
- lrd
- lsl
- ltl
- lvl
- lyd
- mad
- mdl
- mga
- mkd
- mmk
- mnt
- mop
- mro
- mur
- mvr
- mwk
- mxn
- myr
- mzn
- nad
- ngn
- nio
- nok
- npr
- nzd
- omr
- pab
- pen
- pgk
- php
- pkr
- pln
- pyg
- qar
- ron
- rsd
- rub
- rwf
- sar
- sbd
- scr
- sdg
- sek
- sgd
- shp
- sll
- sos
- srd
- std
- svc
- syp
- szl
- thb
- tjs
- tmt
- tnd
- top
- try
- ttd
- twd
- tzs
- uah
- ugx
- usd
- uyu
- uzs
- vef
- ves
- vnd
- vuv
- wst
- xaf
- xag
- xau
- xcd
- xof
- xpf
- yer
- zar
- zmw
- zwl
# CSpell: enable
# These responses are defined primarily to provide examples in the docs
responses:
unauthorizedToken:
description: Unauthorized. This error occurs when an invalid API token is
passed to the request.
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Unauthorized
errors:
- errMsg: Access token does not exist.
rateLimited:
description: Too Many Requests. Retry your request after the number of
seconds specified in the retry-after header.
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Too Many Requests
errors:
- errMsg: Too many requests, please try again later.
serverError:
description: Internal Server Error. Contact support.
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Internal Server Error
errors:
- errMsg: Currently in maintenance mode. Please try again in a few minutes.
securitySchemes:
bearerSecurity:
type: http
# TODO Make this shorter?
# description: The Lunch Money API uses API keys to authenticate requests. To use
# the v1 API you can view and manage your API keys on the [developers page
# in the Lunch Money app](https://my.lunchmoney.app/developers).
To # interact with the Static Mock Server simply enter an API key of 11 # characters or more.
To interact with the v2 service implemented on # top of the v1 API paste in a real API token associated with a Lunch # Money Budget. description: To interact with the Static Mock Server simply enter an API key of 11 characters or more. scheme: bearer bearerFormat: JWT cookieAuth: type: apiKey in: cookie name: _lm_access_token paths: /me: get: tags: - me summary: Get current user description: |- Get details about the user associated with the supplied authorization token.
For account- and user-level preferences, prefer [/me/account/settings](#tag/me/GET/me/account/settings) and [/me/user/settings](#tag/me/GET/me/user/settings). Properties such as `primary_currency` and `budget_name` remain on this response for backwards compatibility. operationId: getMe parameters: [] responses: "200": description: The User Object associated with the authorized token. content: application/json: schema: $ref: "#/components/schemas/userObject" example: name: User 1 email: user-1@lunchmoney.dev id: 18328 account_id: 18221 budget_name: \U0001F3E0 Family budget primary_currency: usd api_key_label: Side project dev key "401": $ref: "#/components/responses/unauthorizedToken" "429": $ref: "#/components/responses/rateLimited" "500": $ref: "#/components/responses/serverError" /me/account/settings: get: tags: - me summary: Get account settings description: Returns account-level settings for the budgeting account associated with the authorized API token. operationId: getAccountSettings responses: "200": description: Account settings for the current budgeting account content: application/json: schema: $ref: "#/components/schemas/accountSettingsObject" example: primary_currency: usd supported_currencies: - usd - cad - jpy display_name: "\U0001F3E0 Family budget" locale: en-US auto_create_category_rules: true auto_create_suggested_transaction_rules: true auto_review_transaction_on_update: true auto_review_transaction_on_creation: true "401": $ref: "#/components/responses/unauthorizedToken" "429": $ref: "#/components/responses/rateLimited" "500": $ref: "#/components/responses/serverError" put: tags: - me summary: Update account settings description: |- Updates account-level settings for the budgeting account associated with the authorized API token.
You may submit the response from a `GET /me/account/settings` as the request body; however, only certain properties can be updated.
It is also possible to provide only the properties to be updated in the request body, as long as the request includes at least one updatable property. operationId: updateAccountSettings requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/updateAccountSettingsRequestObject" examples: Update display name: value: display_name: "Travel budget" Update automation preferences: value: auto_create_category_rules: false auto_review_transaction_on_creation: false responses: "200": description: Account settings updated successfully content: application/json: schema: $ref: "#/components/schemas/accountSettingsObject" "400": description: Invalid request body content: application/json: schema: $ref: "#/components/schemas/errorResponseObject" "401": $ref: "#/components/responses/unauthorizedToken" "429": $ref: "#/components/responses/rateLimited" "500": $ref: "#/components/responses/serverError" /me/user/settings: get: tags: - me summary: Get user settings description: Returns user-level display and formatting preferences for the user associated with the authorized API token. operationId: getUserSettings responses: "200": description: User settings for the authorized user content: application/json: schema: $ref: "#/components/schemas/userSettingsObject" example: show_debits_as_negative: true auto_suggest_payee: true month_year_format: "MMM YYYY" month_day_year_format: "MMM D, YYYY" month_day_format: "MMM D" show_am_pm: true week_starts_on: sunday always_display_year: false always_display_weekday: true "401": $ref: "#/components/responses/unauthorizedToken" "429": $ref: "#/components/responses/rateLimited" "500": $ref: "#/components/responses/serverError" put: tags: - me summary: Update user settings description: |- Updates user-level display and formatting preferences for the user associated with the authorized API token.
You may submit the response from a `GET /me/user/settings` as the request body; however, only certain properties can be updated.
It is also possible to provide only the properties to be updated in the request body, as long as the request includes at least one updatable property.
Updating `show_debits_as_negative` affects display in the Lunch Money app only. Amount fields in API responses always use positive values for debits and negative values for credits. operationId: updateUserSettings requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/updateUserSettingsRequestObject" examples: Update date formats: value: month_year_format: "YYYY-MM" month_day_year_format: "YYYY-MM-DD" month_day_format: "MM-DD" Use 24-hour time and Monday week start: value: show_am_pm: false week_starts_on: monday responses: "200": description: User settings updated successfully content: application/json: schema: $ref: "#/components/schemas/userSettingsObject" "400": description: Invalid request body content: application/json: schema: $ref: "#/components/schemas/errorResponseObject" "401": $ref: "#/components/responses/unauthorizedToken" "429": $ref: "#/components/responses/rateLimited" "500": $ref: "#/components/responses/serverError" /summary: get: tags: - summary summary: Get summary description: Retrieves a summary of the user's budget. Use this endpoint to access budget configuration details and performance for a specified date range.
Use the [/budgets](#tag/budgets) endpoint to manage
budget objects.
operationId: getBudgetSummary
parameters:
- in: query
name: start_date
description: Start of date range in ISO 8601 date format (YYYY-MM-DD).
required: true
schema:
type: string
format: date
examples:
"aligned monthly":
summary: "Start date for monthly budget period"
description: "First day of month for aligned budget periods"
value: "2025-07-01"
"not aligned":
summary: "Start date for non-aligned period"
description: "Date that doesn't align with budget periods"
value: "2025-07-02"
- in: query
name: end_date
description: "End of date range in ISO 8601 date format (YYYY-MM-DD)."
required: true
schema:
type: string
format: date
examples:
"aligned monthly":
summary: "End date for monthly budget period"
description: "Last day of month for aligned budget periods"
value: "2025-08-31"
"not aligned":
summary: "End date for non-aligned period"
description: "Date that doesn't align with budget periods"
value: "2025-08-27"
- in: query
name: include_exclude_from_budgets
description: Enable to include categories that have the 'Exclude from
Budgets' flag set in the returned `categories` array.
required: false
schema:
type: boolean
default: false
- in: query
name: include_occurrences
description: Enable to include an `occurrences` array for each
category in an aligned response. Each array will include an object
for each budget period that falls within the specified date range
which includes details on the activity for the budget period.
required: false
schema:
type: boolean
default: false
- in: query
name: include_past_budget_dates
description: "Enable to include the three budget occurrences prior to
the start date in the `occurrences` array for each category in an
aligned response. This property is ignored if `include_occurrences`
is not also set to `true`."
required: false
schema:
type: boolean
default: false
- in: query
name: include_totals
description: "Enable to include a top-level `totals` section that
summarizes the inflow and outflow across all transactions for the
specified date range."
required: false
schema:
type: boolean
default: false
- in: query
name: include_rollover_pool
description: "Enable to include a `rollover_pool` section that
summarizes the current rollover pool balance and all previous
adjustments."
required: false
schema:
type: boolean
default: false
responses:
"200":
description: "Summary of the user's budget for the specified date
range."
content:
application/json:
schema:
$ref: "#/components/schemas/summaryResponseObject"
examples:
"aligned monthly":
summary: "Monthly budget summary aligned with budget periods"
description: "Example response for a date range that aligns
with monthly budget periods (1st to last day of month) with
occurrences included"
value:
aligned: true
categories:
- category_id: 315177
totals:
other_activity: 156.64
recurring_activity: 0
budgeted: 500
available: 343.36
recurring_remaining: 0
recurring_expected: 0
occurrences:
- in_range: true
start_date: "2025-07-01"
end_date: "2025-07-31"
other_activity: 156.64
recurring_activity: 0
budgeted: 500
budgeted_amount: "500.0000"
budgeted_currency: "usd"
notes: "Monthly budget allocation"
- in_range: true
start_date: "2025-08-01"
end_date: "2025-08-31"
other_activity: 0
recurring_activity: 0
budgeted: 500
budgeted_amount: "500.0000"
budgeted_currency: "usd"
notes: "Adjusted for seasonal spending"
- category_id: 315628
totals:
other_activity: 424.8
recurring_activity: 0
budgeted: 200
available: -224.8
recurring_remaining: 0
recurring_expected: 0
occurrences:
- in_range: true
start_date: "2025-07-01"
end_date: "2025-07-31"
other_activity: 424.8
recurring_activity: 0
budgeted: 200
budgeted_amount: "200.0000"
budgeted_currency: "usd"
notes: "Based on previous month's activity"
- in_range: true
start_date: "2025-08-01"
end_date: "2025-08-31"
other_activity: 0
recurring_activity: 0
budgeted: 200
budgeted_amount: "200.0000"
budgeted_currency: "usd"
notes: "Emergency fund contribution"
- category_id: 86
totals:
other_activity: 25.69
recurring_activity: 0
budgeted: 200
available: 174.31
recurring_remaining: 0
recurring_expected: 0
occurrences:
- in_range: true
start_date: "2025-07-01"
end_date: "2025-07-31"
other_activity: 25.69
recurring_activity: 0
budgeted: 200
budgeted_amount: "200.0000"
budgeted_currency: "usd"
notes: "Holiday spending budget"
- in_range: true
start_date: "2025-08-01"
end_date: "2025-08-31"
other_activity: 0
recurring_activity: 0
budgeted: 200
budgeted_amount: "200.0000"
budgeted_currency: "usd"
notes: "Summer vacation savings"
"not aligned":
summary: "Budget summary for non-aligned date range"
description: "Example response for a date range that does not
align with monthly budget periods (July 2 to August 27)"
value:
aligned: false
categories:
- category_id: 315177
totals:
other_activity: 156.64
recurring_activity: 0
budgeted: 400
available: 243.36
recurring_remaining: 0
recurring_expected: 0
- category_id: 315628
totals:
other_activity: 424.8
recurring_activity: 0
budgeted: null
available: null
recurring_remaining: 0
recurring_expected: 0
- category_id: 78
totals:
other_activity: 0
recurring_activity: 0
budgeted: null
available: null
recurring_remaining: 0
recurring_expected: 0
- category_id: 83
totals:
other_activity: 0
recurring_activity: 0
budgeted: null
available: null
recurring_remaining: 1700
recurring_expected: 1700
- category_id: 88
totals:
other_activity: 0
recurring_activity: 2501.68
budgeted: null
available: null
recurring_remaining: 0
recurring_expected: 2501.68
- category_id: 86
totals:
other_activity: 25.69
recurring_activity: 0
budgeted: 200
available: 174.31
recurring_remaining: 0
recurring_expected: 0
- category_id: 84
totals:
other_activity: 401.12
recurring_activity: 4.13
budgeted: 150
available: -255.25
recurring_remaining: -4.13
recurring_expected: 0
"summarized totals":
summary: "Monthly budget summary with totals included"
description: "Example response for aligned monthly budget
periods with totals section showing overall inflow and
outflow"
value:
aligned: true
categories:
- category_id: 315177
totals:
other_activity: 156.64
recurring_activity: 0
budgeted: 400
available: 243.36
recurring_remaining: 0
recurring_expected: 0
occurrences:
- in_range: true
start_date: "2025-07-01"
end_date: "2025-07-31"
other_activity: 156.64
recurring_activity: 0
budgeted: 400
budgeted_amount: "400.0000"
budgeted_currency: "usd"
notes: "Monthly budget allocation"
- category_id: 315628
totals:
other_activity: 424.8
recurring_activity: 0
budgeted: 200
available: -224.8
recurring_remaining: 0
recurring_expected: 0
occurrences:
- in_range: true
start_date: "2025-07-01"
end_date: "2025-07-31"
other_activity: 424.8
recurring_activity: 0
budgeted: 200
budgeted_amount: "200.0000"
budgeted_currency: "usd"
notes: "Based on previous month's activity"
- category_id: 315629
totals:
other_activity: 0
recurring_activity: 0
budgeted: 150
available: 150
recurring_remaining: 0
recurring_expected: 0
occurrences:
- in_range: true
start_date: "2025-07-01"
end_date: "2025-07-31"
other_activity: 0
recurring_activity: 0
budgeted: 150
budgeted_amount: "150.0000"
budgeted_currency: "usd"
notes: "Emergency fund contribution"
totals:
inflow:
other_activity: -125.50
recurring_activity: -89.99
uncategorized: 0
uncategorized_count: 0
uncategorized_recurring: 0
outflow:
other_activity: 581.44
recurring_activity: 0
uncategorized: 45.20
uncategorized_count: 3
uncategorized_recurring: 0
"with occurrences":
summary: "Monthly budget summary with occurrences included"
description: "Example response for aligned monthly budget
periods with occurrences showing individual budget period
details for each category"
value:
aligned: true
categories:
- category_id: 315177
totals:
other_activity: 156.64
recurring_activity: 0
budgeted: 500
available: 343.36
recurring_remaining: 0
recurring_expected: 0
occurrences:
- in_range: true
start_date: "2025-07-01"
end_date: "2025-07-31"
other_activity: 156.64
recurring_activity: 0
budgeted: 500
budgeted_amount: "500.0000"
budgeted_currency: "usd"
notes: "Monthly budget allocation"
- in_range: true
start_date: "2025-08-01"
end_date: "2025-08-31"
other_activity: 0
recurring_activity: 0
budgeted: 500
budgeted_amount: "500.0000"
budgeted_currency: "usd"
notes: "Adjusted for seasonal spending"
- category_id: 315628
totals:
other_activity: 424.8
recurring_activity: 0
budgeted: 200
available: -224.8
recurring_remaining: 0
recurring_expected: 0
occurrences:
- in_range: true
start_date: "2025-07-01"
end_date: "2025-07-31"
other_activity: 424.8
recurring_activity: 0
budgeted: 200
budgeted_amount: "200.0000"
budgeted_currency: "usd"
notes: "Based on previous month's activity"
- in_range: true
start_date: "2025-08-01"
end_date: "2025-08-31"
other_activity: 0
recurring_activity: 0
budgeted: 200
budgeted_amount: "200.0000"
budgeted_currency: "usd"
notes: "Emergency fund contribution"
- category_id: 86
totals:
other_activity: 25.69
recurring_activity: 0
budgeted: 200
available: 174.31
recurring_remaining: 0
recurring_expected: 0
occurrences:
- in_range: true
start_date: "2025-07-01"
end_date: "2025-07-31"
other_activity: 25.69
recurring_activity: 0
budgeted: 200
budgeted_amount: "200.0000"
budgeted_currency: "usd"
notes: "Holiday spending budget"
- in_range: true
start_date: "2025-08-01"
end_date: "2025-08-31"
other_activity: 0
recurring_activity: 0
budgeted: 200
budgeted_amount: "200.0000"
budgeted_currency: "usd"
notes: "Summer vacation savings"
"with past occurrences":
summary: "Monthly budget summary with past occurrences included"
description: "Example response for aligned monthly budget
periods with include_past_budget_dates=true, showing 3 past
occurrences with in_range: false"
value:
aligned: true
categories:
- category_id: 315177
totals:
other_activity: 156.64
recurring_activity: 0
budgeted: 500
available: 343.36
recurring_remaining: 0
recurring_expected: 0
occurrences:
- in_range: false
start_date: "2025-04-01"
end_date: "2025-04-30"
other_activity: 120.50
recurring_activity: 0
budgeted: 500
budgeted_amount: "500.0000"
budgeted_currency: "usd"
notes: "Monthly budget allocation"
- in_range: false
start_date: "2025-05-01"
end_date: "2025-05-31"
other_activity: 180.25
recurring_activity: 0
budgeted: 500
budgeted_amount: "500.0000"
budgeted_currency: "usd"
notes: null
- in_range: false
start_date: "2025-06-01"
end_date: "2025-06-30"
other_activity: 200.00
recurring_activity: 0
budgeted: 500
budgeted_amount: "500.0000"
budgeted_currency: "usd"
notes: "Adjusted for seasonal spending"
- in_range: true
start_date: "2025-07-01"
end_date: "2025-07-31"
other_activity: 156.64
recurring_activity: 0
budgeted: 500
budgeted_amount: "500.0000"
budgeted_currency: "usd"
notes: "Monthly budget allocation"
"with rollover pool":
summary: "Monthly budget summary with rollover pool included"
description: "Example response for aligned monthly budget
periods with include_rollover_pool=true, showing rollover
pool data for categories with budgets"
value:
aligned: true
rollover_pool:
budgeted_to_base: 179.50
all_adjustments:
- in_range: false
date: "2025-06-30"
amount: "179.5000"
currency: "usd"
to_base: 179.50
- in_range: false
date: "2025-05-31"
amount: "120.2500"
currency: "usd"
to_base: 120.25
- in_range: false
date: "2025-04-30"
amount: "80.0000"
currency: "usd"
to_base: 80.00
categories:
- category_id: 315177
totals:
other_activity: 156.64
recurring_activity: 0
budgeted: 500
available: 343.36
recurring_remaining: 0
recurring_expected: 0
occurrences:
- in_range: true
start_date: "2025-07-01"
end_date: "2025-07-31"
other_activity: 156.64
recurring_activity: 0
budgeted: 500
budgeted_amount: "500.0000"
budgeted_currency: "usd"
notes: "Monthly budget allocation"
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/categories:
get:
tags:
- categories
summary: Get all categories
description: Retrieve a list of all categories associated with the user's
account.
operationId: getAllCategories
parameters:
- name: format
in: query
description: If `nested`, returns top-level categories (either
category groups or categories not part of a category group) in
alphabetical order. Grouped categories are nested within the
category group under the property `children`. A `flattened`,
response is similar but it includes grouped categories at the top
level.
Categories are sorted by their `order`. When
`order` is null, they are listed in alphabetical order below other
categories with an `order`.
required: false
schema:
type: string
default: nested
enum:
- nested
- flattened
- name: is_group
in: query
description: If `false`, only categories not part of a category group
are returned.
If `true`, only category groups are returned.
When set, the `format` parameter is ignored.
required: false
schema:
type: boolean
responses:
"200":
description: A list of Category Objects
content:
application/json:
schema:
type: object
properties:
categories:
type: array
items:
$ref: "#/components/schemas/categoryObject"
examples:
nested response:
value:
categories:
- id: 86
name: Automobile
description: Auto related categories
is_income: false
exclude_from_budget: false
exclude_from_totals: false
updated_at: "2025-02-28T09:49:03.238Z"
created_at: "2025-01-28T09:49:03.238Z"
is_group: true
order: 2
collapsed: false
archived: false
group_id: null
archived_at: null
children:
- id: 315174
name: Fuel
description: Fuel and gas expenses
is_income: false
exclude_from_budget: false
exclude_from_totals: false
updated_at: "2025-02-28T09:49:03.238Z"
created_at: "2025-01-28T09:49:03.238Z"
is_group: false
order: 1
collapsed: false
archived: false
group_id: 86
archived_at: null
- id: 315175
name: Maintenance
description: Car maintenance and repairs
is_income: false
exclude_from_budget: false
exclude_from_totals: false
updated_at: "2025-02-28T09:49:03.238Z"
created_at: "2025-01-28T09:49:03.238Z"
is_group: false
order: 2
collapsed: false
archived: false
group_id: 86
archived_at: null
- id: 83
name: Rent
description: Monthly Rent
is_income: false
exclude_from_budget: false
exclude_from_totals: false
updated_at: "2025-02-28T09:49:03.225Z"
created_at: "2025-01-28T09:49:03.225Z"
is_group: false
order: 0
collapsed: false
archived: false
group_id: null
archived_at: null
- id: 88
name: W2 Income
description: null
is_income: true
exclude_from_budget: false
exclude_from_totals: true
updated_at: "2025-02-28T09:49:03.238Z"
created_at: "2025-01-28T09:49:03.238Z"
is_group: false
order: 3
collapsed: false
archived: false
group_id: null
archived_at: null
flattened response:
value:
categories:
- id: 86
name: Automobile
description: Auto related categories
is_income: false
exclude_from_budget: false
exclude_from_totals: false
updated_at: "2025-02-28T09:49:03.238Z"
created_at: "2025-01-28T09:49:03.238Z"
is_group: true
order: 1
collapsed: false
archived: false
group_id: null
archived_at: null
children:
- id: 315174
name: Fuel
description: Fuel and gas expenses
is_income: false
exclude_from_budget: false
exclude_from_totals: false
updated_at: "2025-02-28T09:49:03.238Z"
created_at: "2025-01-28T09:49:03.238Z"
is_group: false
order: 1
collapsed: false
archived: false
group_id: 86
archived_at: null
- id: 315175
name: Maintenance
description: Car maintenance and repairs
is_income: false
exclude_from_budget: false
exclude_from_totals: false
updated_at: "2025-02-28T09:49:03.238Z"
created_at: "2025-01-28T09:49:03.238Z"
is_group: false
order: 2
collapsed: false
archived: false
group_id: 86
archived_at: null
- id: 315174
name: Fuel
description: Fuel and gas expenses
is_income: false
exclude_from_budget: false
exclude_from_totals: false
updated_at: "2025-02-28T09:49:03.238Z"
created_at: "2025-01-28T09:49:03.238Z"
is_group: false
order: 1
collapsed: false
archived: false
group_id: 86
archived_at: null
- id: 315175
name: Maintenance
description: Car maintenance and repairs
is_income: false
exclude_from_budget: false
exclude_from_totals: false
updated_at: "2025-02-28T09:49:03.238Z"
created_at: "2025-01-28T09:49:03.238Z"
is_group: false
order: 2
collapsed: false
archived: false
group_id: 86
archived_at: null
- id: 83
name: Rent
description: Monthly Rent
is_income: false
exclude_from_budget: false
exclude_from_totals: false
updated_at: "2025-02-28T09:49:03.225Z"
created_at: "2025-01-28T09:49:03.225Z"
is_group: false
order: 2
collapsed: false
archived: false
group_id: null
archived_at: null
- id: 88
name: W2 Income
description: null
is_income: true
exclude_from_budget: false
exclude_from_totals: true
updated_at: "2025-02-28T09:49:03.238Z"
created_at: "2025-01-28T09:49:03.238Z"
is_group: false
order: 3
collapsed: false
archived: false
group_id: null
archived_at: null
"400":
description: Invalid request parameters
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Request Validation Failure
errors:
- errMsg: must be equal to one of the allowed values
instancePath: /query/format
schemaPath: "#/properties/query/properties/format/enum"
keyword: enum
params:
allowedValues:
- flattened
- nested
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
post:
tags:
- categories
summary: Create a new category or category group
description: Creates a new category with the given name.
If the
`is_group` attribute is set to true, a category group is created. In
this case, the `children` attribute may be set to an array of category
IDs to add to the newly created category group.
operationId: createCategory
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/createCategoryRequestObject"
examples:
category:
value:
name: API Created Category
description: Test description of created category
is_income: false
exclude_from_budget: true
exclude_from_totals: false
is_group: false
category group:
value:
name: API Created Category Group
description: Test description of Category Group
is_income: false
exclude_from_budget: false
exclude_from_totals: false
is_group: true
children:
- 83
responses:
"201":
description: Category or Category Group Object with the successfully
created category or category group.
content:
application/json:
schema:
$ref: "#/components/schemas/categoryObject"
examples:
category:
value:
id: 90
name: API Created Category
description: Test description of created category
is_income: false
exclude_from_budget: true
exclude_from_totals: false
updated_at: "2025-05-26T19:56:52.699Z"
created_at: "2025-05-26T19:56:52.699Z"
is_group: false
group_id: null
archived: false
archived_at: null
order: null
collapsed: false
category group:
value:
id: 91
name: API Created Category Group
description: Test description of Category Group
is_income: false
exclude_from_budget: false
exclude_from_totals: false
updated_at: "2025-05-27T19:59:45.053Z"
created_at: "2025-05-27T19:59:45.053Z"
is_group: true
group_id: null
archived: false
archived_at: null
order: null
collapsed: false
children:
- id: 83
name: Rent
description: Monthly Rent
is_income: false
exclude_from_budget: false
exclude_from_totals: false
updated_at: "2025-02-28T09:49:03.225Z"
created_at: "2025-01-28T09:49:03.225Z"
is_group: false
order: 1
collapsed: false
archived: false
group_id: null
archived_at: null
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Invalid Request Body
errors:
- errMsg: Cannot specify a 'group_id' in request body if 'is_group' is also true
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/categories/{id}:
get:
tags:
- categories
summary: Get a single category
description: Retrieve details of a specific category or category group by
its ID.
operationId: getCategoryById
parameters:
- name: id
in: path
description: ID of the category to retrieve
required: true
schema:
type: integer
format: int32
examples:
category:
summary: Example of a category's id
value: 315174
category group:
summary: Example of a category group's id
value: 86
id not found:
summary: Example of an id that doesn't exist
value: 543210
responses:
"201":
description: Category Object with the requested category or category
group.
content:
application/json:
schema:
$ref: "#/components/schemas/categoryObject"
examples:
category:
value:
id: 315174
name: Fuel
description: Fuel and gas expenses
is_income: false
exclude_from_budget: false
exclude_from_totals: false
updated_at: "2025-02-28T09:49:03.238Z"
created_at: "2025-01-28T09:49:03.238Z"
group_id: 86
is_group: false
archived: false
archived_at: null
order: 1
collapsed: false
category group:
value:
id: 86
name: Automobile
description: Auto related categories
is_income: false
exclude_from_budget: false
exclude_from_totals: false
updated_at: "2025-02-28T09:49:03.238Z"
created_at: "2025-01-28T09:49:03.238Z"
is_group: true
order: 2
collapsed: false
archived: false
group_id: null
archived_at: null
children:
- id: 315174
name: Fuel
description: Fuel and gas expenses
is_income: false
exclude_from_budget: false
exclude_from_totals: false
updated_at: "2025-02-28T09:49:03.238Z"
created_at: "2025-01-28T09:49:03.238Z"
group_id: 86
is_group: false
archived: false
archived_at: null
order: 1
collapsed: false
- id: 315175
name: Maintenance
description: Car maintenance and repairs
is_income: false
exclude_from_budget: false
exclude_from_totals: false
updated_at: "2025-02-28T09:49:03.238Z"
created_at: "2025-01-28T09:49:03.238Z"
group_id: 86
is_group: false
archived: false
archived_at: null
order: 2
collapsed: false
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Request Validation Failure
errors:
- errMsg: must be a valid integer
instancePath: /query/ids/0
schemaPath: "#/properties/query/properties/ids/items/type"
keyword: type
params:
type: integer
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no category with the id: 543210."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
put:
tags:
- categories
summary: Update an existing category or category group
description: >-
Modifies the properties of an existing category or category group.
You may submit the response from a `GET /categories/{id}` as the request body; however, only certain
properties can be updated using this API. The following properties are
accepted in the request body but their values will be ignored: `id`, `is_group`, `updated_at`, `created_at`, and `order`.
It is also possible to provide only the properties to be updated in the
request body, as long as the request includes at least one of the
properties that is not listed above. For example, a request body that contains only a `name` property is valid.
It is not possible to use this API to convert a category to a category group, or vice versa, so while submitting a request body with the `is_group` property is tolerated, it will result in an error response if the value is changed.
It is possible to modify the children of an existing category group with this API by setting the `children` attribute. If this is set, it will replace the existing children with the newly specified children. If the intention is to add or remove a single category, it is more straightforward to update the child category by specifying the new `group_id` attribute. If the goal is to add multiple new children or remove multiple existing children, it is recommended to first call the `GET /categories/{id}` endpoint to get the existing children and then modify the list as desired.
operationId: updateCategory
parameters:
- name: id
in: path
description: ID of the category to update
required: true
schema:
type: integer
format: int32
examples:
category:
summary: Example of a category's id
value: 83
category group:
summary: Example of a category group's id
value: 86
child category:
summary: Example of a category belonging to a group
value: 315164
not found:
summary: Example of a category id that does not exist
value: 543210
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/updateCategoryRequestObject"
examples:
Update some category properties:
value:
name: Updated Category Name
description: Updated description of the category
Update same properties with full object:
value:
id: 83
name: Updated Category Name
description: Updated description of the category
is_income: false
exclude_from_budget: true
exclude_from_totals: false
updated_at: "2020-01-28T09:49:03.225Z"
created_at: "2020-01-28T09:49:03.225Z"
is_group: false
group_id: null
archived: false
archived_at: null
order: 0
Invalid attempt to convert to category group:
value:
id: 83
name: Old Category is now a group!
is_group: true
Remove category from a group:
value:
id: 86
name: Automobile
description: API Removed a sub category
children:
- 315174
responses:
"200":
description: Category or Category Group updated successfully
content:
application/json:
schema:
$ref: "#/components/schemas/categoryObject"
examples:
category:
value:
id: 83
name: Updated Category Name
description: Updated description of the category
is_income: false
exclude_from_budget: false
exclude_from_totals: true
updated_at: "2025-05-26T20:41:18.406Z"
created_at: "2025-01-28T09:49:03.225Z"
is_group: false
order: 0
collapsed: false
archived: false
archived_at: null
group_id: null
category group:
value:
id: 86
name: Automobile
description: API Removed a sub category
is_income: false
exclude_from_budget: false
exclude_from_totals: false
updated_at: "2025-06-22T19:54:30.921Z"
created_at: "2025-01-28T09:49:03.238Z"
is_group: true
order: 2
collapsed: false
archived: false
group_id: null
archived_at: null
children:
- id: 315174
name: Fuel
description: Fuel and gas expenses
is_income: false
exclude_from_budget: false
exclude_from_totals: false
updated_at: "2025-02-28T09:49:03.238Z"
created_at: "2025-01-28T09:49:03.238Z"
group_id: 86
is_group: false
archived: false
archived_at: null
order: 1
collapsed: false
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Invalid Request Body
errors:
- errMsg: Cannot modify the 'group_id' property of an existing category or
category group
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no category with the id: 543210."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
delete:
tags:
- categories
summary: Delete a category or category group
description: Attempts to delete the single category or category group
specified on the path. By default, this will only work if there are no
dependencies, such as existing budgets for the category, categorized
transactions, child categories for a category group, categorized
recurring items, etc. If there are dependents, this endpoint will return
an object that describes the number and type of existing dependencies.
operationId: deleteCategory
parameters:
- in: path
name: id
description: ID of the category to delete
required: true
schema:
type: integer
format: int32
examples:
delete category:
summary: Simple category delete
value: 83
delete category group:
summary: Attempt to delete category with dependencies
value: 84
id not found:
summary: Example of an id that doesn't exist
value: 543210
- in: query
name: force
description: Set to `true` to force deletion even if there are
dependencies
required: false
schema:
type: boolean
default: false
responses:
"204":
description: No Content
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no category with the id: 543210."
"422":
description: Unprocessable Content
content:
application/json:
schema:
$ref: "#/components/schemas/deleteCategoryResponseWithDependencies"
examples:
delete category with dependencies:
summary: Response to an attempt to delete category with dependencies
value:
category_name: Category to be Deleted
dependents:
budget: 0
category_rules: 1
transactions: 10
children: 0
recurring: 0
plaid_cats: 0
delete category group:
summary: Response to attempt to delete a category group with children
value:
category_name: Category Group to be Deleted
dependents:
budget: 0
category_rules: 0
transactions: 0
children: 3
recurring: 0
plaid_cats: 0
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/cryptocurrencies:
get:
tags:
- crypto-manual
summary: Get all supported cryptocurrencies
description: >
Retrieve the list of cryptocurrencies currently supported for manual tracking.
When creating a new manual crypto balance via `POST /crypto/manual`, the
`symbol` you specify must match the `symbol` of one of the entries
returned by this endpoint.
operationId: getAllCryptocurrencies
responses:
"200":
description: A list of supported cryptocurrencies
content:
application/json:
schema:
$ref: "#/components/schemas/cryptoCurrencyResponseObject"
example:
cryptocurrencies:
- id: 1
coingecko_id: bitcoin
symbol: btc
full_name: Bitcoin
- id: 2
coingecko_id: ethereum
symbol: eth
full_name: Ethereum
- id: 3
coingecko_id: solana
symbol: sol
full_name: Solana
- id: 4
coingecko_id: ripple
symbol: xrp
full_name: XRP
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
post:
tags:
- crypto-manual
summary: Add a new supported cryptocurrency
operationId: createCryptocurrency
description: >-
Adds a new cryptocurrency to the supported manual-crypto list.
Lunch Money uses [CoinGecko](https://www.coingecko.com/us/coins/ethereum)
to convert crypto balances to the user's primary currency. Users add a
new supported cryptocurrency by submitting a CoinGecko coin-page URL.
The server validates the URL, extracts the id from `/coins/{id}`,
checks for an existing supported `coingecko_id`, validates the id
against CoinGecko, then confirms the resolved symbol is not already
supported before creating the new entry.
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/createCryptocurrencyRequestObject"
examples:
by CoinGecko url:
value:
coingecko_url: https://www.coingecko.com/fr/coins/cardano
responses:
"201":
description: Supported cryptocurrency created successfully
content:
application/json:
schema:
$ref: "#/components/schemas/cryptoCurrencyObject"
example:
id: 5
coingecko_id: cardano
symbol: ada
full_name: Cardano
"400":
description: Invalid request body
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
unexpected property:
value:
message: Invalid Request Body
errors:
- errMsg: "Invalid property 'foo' in request body."
"422":
description: Request validation failure
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
malformed CoinGecko url:
value:
message: Request Validation Failure
errors:
- errMsg: "Malformed coingecko_url. Expected a URL like 'https://www.coingecko.com/en/coins/ethereum'."
existing id conflict:
value:
message: Request Validation Failure
errors:
- errMsg: "The coingecko_id 'bitcoin' is already in our supported currency database."
existing_coingecko_id: bitcoin
existing_symbol: btc
invalid CoinGecko id:
value:
message: Request Validation Failure
errors:
- errMsg: "Unable to determine cryptocurrency from url"
coingecko_url: https://www.coingecko.com/en/coins/xyz
CoinGecko mapped to existing symbol:
value:
message: Request Validation Failure
errors:
- errMsg: "The coingecko_id 'bitcoin-avalanche-bridged-btc-b' is already in our supported currency database."
existing_coingecko_id: bitcoin-avalanche-bridged-btc-b
existing_symbol: btc.b
coingecko_url: https://www.coingecko.com/en/coins/bitcoin-avalanche-bridged-btc-b
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/crypto/manual:
get:
tags:
- crypto-manual
summary: Get all manual crypto balances
description: Retrieve all manually managed crypto balances associated with
the user's account.
operationId: getAllCryptoManual
responses:
"200":
description: A list of manual crypto balances
content:
application/json:
schema:
$ref: "#/components/schemas/cryptoManualListResponseObject"
example:
crypto_manual:
- id: 22001
name: Cold Wallet BTC
display_name: Long-term BTC
institution_name: Ledger
balance: "0.852341920145782301"
symbol: btc
coingecko_id: bitcoin
to_base: 53124.72
balance_as_of: "2026-02-25T14:22:10.000Z"
exchange_rate_as_of: "2026-02-25T14:10:00.000Z"
created_by_name: User 1
created_at: "2025-11-12T20:14:32.000Z"
updated_at: "2026-02-25T14:22:10.000Z"
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
post:
tags:
- crypto-manual
summary: Create a manual crypto balance
description: >-
Create a manually managed crypto asset.
If `display_name` is `null`, clients may derive one from
`institution_name` + `name`.
operationId: createCryptoManual
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/createCryptoManualRequestObject"
examples:
minimum request body:
summary: Minimum required fields
value:
name: Cold Wallet BTC
balance: "0.852341920145782301"
symbol: btc
full request body:
summary: Full example with optional display fields
value:
name: Coinbase ETH Holdings
display_name: Trading ETH
institution_name: Coinbase
balance: "12.004500000000000000"
symbol: eth
responses:
"201":
description: Manual crypto balance created successfully
content:
application/json:
schema:
$ref: "#/components/schemas/cryptoManualObject"
example:
id: 22045
name: Coinbase ETH Holdings
display_name: Trading ETH
institution_name: Coinbase
balance: "12.004500000000000000"
symbol: eth
coingecko_id: ethereum
to_base: 28998.44
balance_as_of: "2026-03-01T09:20:41.000Z"
exchange_rate_as_of: "2026-03-01T09:15:00.000Z"
created_by_name: User 1
created_at: "2026-03-01T09:20:41.000Z"
updated_at: "2026-03-01T09:20:41.000Z"
"400":
description: Invalid request body
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
missing required properties:
value:
message: Invalid Request Body
errors:
- errMsg: "Missing required property 'name' in request body."
- errMsg: "Missing required property 'balance' in request body."
- errMsg: "Missing required property 'symbol' in request body."
invalid balance:
value:
message: Invalid Request Body
errors:
- errMsg: "Invalid value for property 'balance'. 'abc' cannot be converted to a number"
- errMsg: "Invalid value for property 'balance'. Invalid input"
invalid property:
value:
message: Invalid Request Body
errors:
- errMsg: "Invalid property 'coingecko_id' in request body."
unsupported symbol:
value:
message: Request Validation Failure
errors:
- errMsg: "Unsupported crypto symbol 'doge'. Use GET /cryptocurrencies to find a supported symbol."
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/crypto/manual/{id}:
get:
tags:
- crypto-manual
summary: Get a single manual crypto balance
description: Retrieve a single manually managed crypto balance by ID.
operationId: getCryptoManualById
parameters:
- name: id
in: path
description: ID of the manual crypto balance to retrieve
required: true
schema:
type: integer
format: int32
examples:
existing manual crypto:
summary: Existing manual crypto ID
value: 22001
id not found:
summary: Example of an id that doesn't exist
value: 99999999
responses:
"200":
description: Manual crypto balance object
content:
application/json:
schema:
$ref: "#/components/schemas/cryptoManualObject"
example:
id: 22001
name: Cold Wallet BTC
display_name: Long-term BTC
institution_name: Ledger
balance: "0.852341920145782301"
symbol: btc
coingecko_id: bitcoin
to_base: 53124.72
balance_as_of: "2026-02-25T14:22:10.000Z"
exchange_rate_as_of: "2026-02-25T14:10:00.000Z"
created_by_name: User 1
created_at: "2025-11-12T20:14:32.000Z"
updated_at: "2026-02-25T14:22:10.000Z"
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Invalid Path Parameters
errors:
- errMsg: "Invalid value type for path parameter: 'id'. Expected 'number', received 'string'."
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no manual crypto account with the id: 99999999."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
put:
tags:
- crypto-manual
summary: Update a manual crypto balance
description: >-
Modify a manually managed crypto balance.
You may submit the response from `GET /crypto/manual/{id}` as the request body. System-defined properties
are accepted according to the `x-updatable` metadata in the update schema.
operationId: updateCryptoManual
parameters:
- name: id
in: path
description: ID of the manual crypto balance to update
required: true
schema:
type: integer
format: int32
examples:
existing manual crypto:
summary: Existing manual crypto ID
value: 22001
id not found:
summary: Example of an id that doesn't exist
value: 99999999
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/updateCryptoManualRequestObject"
examples:
minimum request body:
summary: Update balance only
value:
balance: "0.900000000000000000"
full get response body:
summary: Full object payload with system fields tolerated
value:
id: 22001
name: Cold Wallet BTC
display_name: Long-term BTC
institution_name: Ledger
balance: "0.900000000000000000"
symbol: btc
coingecko_id: bitcoin
to_base: 56011.12
balance_as_of: "2026-03-01T09:41:18.000Z"
exchange_rate_as_of: "2026-03-01T09:35:00.000Z"
created_by_name: User 1
created_at: "2025-11-12T20:14:32.000Z"
updated_at: "2026-02-25T14:22:10.000Z"
responses:
"200":
description: Manual crypto balance updated successfully
content:
application/json:
schema:
$ref: "#/components/schemas/cryptoManualObject"
example:
id: 22001
name: Cold Wallet BTC
display_name: Long-term BTC
institution_name: Ledger
balance: "0.900000000000000000"
symbol: btc
coingecko_id: bitcoin
to_base: 56011.12
balance_as_of: "2026-03-01T09:41:18.000Z"
exchange_rate_as_of: "2026-03-01T09:35:00.000Z"
created_by_name: User 1
created_at: "2025-11-12T20:14:32.000Z"
updated_at: "2026-03-01T09:41:18.000Z"
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
missing updatable properties:
value:
message: Request Validation Failure
errors:
- errMsg: "A request to update a manual crypto account must include at least one writable property: name, display_name, institution_name, or balance."
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no manual crypto account with the id: 99999999."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
delete:
tags:
- crypto-manual
summary: Delete a manual crypto balance
description: Delete a single manually managed crypto asset by ID.
If
this crypto asset has a balance history, and you do not explicitly set
the query parameter`keep_history`, a 422 response will be returned
requesting you to explicitly set `keep_history` to `true` or `false`.
operationId: deleteCryptoManual
parameters:
- name: id
in: path
description: ID of the manual crypto balance to delete
required: true
schema:
type: integer
format: int32
examples:
existing manual crypto:
summary: Existing manual crypto ID
value: 22001
id not found:
summary: Example of an id that doesn't exist
value: 99999999
- name: keep_history
in: query
description: Explicitly set to `true` to preserve balance history, or
`false` to remove associated history during deletion. This must be
set if the account has a balance history.
required: false
schema:
type: boolean
responses:
"204":
description: No Content. The crypto asset has been deleted.
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no manual crypto balance with the id: 99999999."
"422":
description: Unprocessable Content
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Explicit confirmation required
errors:
- errMsg: This crypto manual account has existing balance history. To delete this account, you must explicitly set keep_history to true or false.
crypto_manual_id: 22001
has_balance_history: true
required_parameter: keep_history
allowed_values:
- true
- false
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/crypto/synced:
get:
tags:
- crypto-synced
summary: Get all synced crypto accounts
description: Retrieves all synced crypto accounts
associated with the user's account.
operationId: getAllCryptoSynced
responses:
"200":
description: A list of synced crypto accounts
content:
application/json:
schema:
$ref: "#/components/schemas/cryptoSyncedListResponseObject"
example:
crypto_synced:
- id: 33004
provider: coinbase
status: active
created_by_name: User 1
created_at: "2025-10-02T11:02:09.000Z"
updated_at: "2026-02-25T14:25:01.000Z"
display_name: Coinbase Main
balances:
- name: ETH
balance: "12.004500000000000000"
symbol: eth
coingecko_id: ethereum
to_base: 28998.44
balance_as_of: "2026-02-25T14:25:00.000Z"
exchange_rate_as_of: "2026-02-25T14:20:00.000Z"
updated_at: "2026-02-25T14:25:01.000Z"
- name: BTC
balance: "0.100020003000400050"
symbol: btc
coingecko_id: bitcoin
to_base: 6231.28
balance_as_of: "2026-02-25T14:25:00.000Z"
exchange_rate_as_of: "2026-02-25T14:20:00.000Z"
updated_at: "2026-02-25T14:25:01.000Z"
- id: 33005
provider: kraken
status: relink
created_by_name: User 1
created_at: "2025-08-10T10:00:00.000Z"
updated_at: "2026-02-26T07:22:30.000Z"
display_name: Kraken Wallet
balances:
- name: XRP
balance: "2500.000000000000000000"
symbol: xrp
coingecko_id: ripple
to_base: 1287.50
balance_as_of: "2026-02-26T07:22:30.000Z"
exchange_rate_as_of: "2026-02-26T07:10:00.000Z"
updated_at: "2026-02-26T07:22:30.000Z"
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/crypto/synced/{id}:
get:
tags:
- crypto-synced
summary: Get a single synced crypto account
description: Retrieves the synced crypto account and all nested balances
for the specified synced crypto account ID.
operationId: getCryptoSyncedById
parameters:
- name: id
in: path
description: Synced crypto account ID
required: true
schema:
type: integer
format: int32
examples:
existing synced connection:
summary: Existing synced account ID
value: 33004
id not found:
summary: Example of an id that doesn't exist
value: 99999999
responses:
"200":
description: Synced crypto account object
content:
application/json:
schema:
$ref: "#/components/schemas/syncedCryptoAccount"
example:
id: 33004
provider: coinbase
status: active
created_by_name: User 1
created_at: "2025-10-02T11:02:09.000Z"
updated_at: "2026-02-25T14:25:01.000Z"
display_name: Coinbase Main
balances:
- name: ETH
balance: "12.004500000000000000"
symbol: eth
coingecko_id: ethereum
to_base: 28998.44
balance_as_of: "2026-02-25T14:25:00.000Z"
exchange_rate_as_of: "2026-02-25T14:20:00.000Z"
updated_at: "2026-02-25T14:25:01.000Z"
- name: BTC
balance: "0.100020003000400050"
symbol: btc
coingecko_id: bitcoin
to_base: 6231.28
balance_as_of: "2026-02-25T14:25:00.000Z"
exchange_rate_as_of: "2026-02-25T14:20:00.000Z"
updated_at: "2026-02-25T14:25:01.000Z"
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Invalid Path Parameters
errors:
- errMsg: "Invalid value type for path parameter: 'id'. Expected 'number', received 'string'."
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no synced crypto account with the id: 99999999."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/crypto/synced/{id}/{symbol}:
get:
tags:
- crypto-synced
summary: Get a synced crypto balance by symbol
description: Retrieves a single balance from the specified synced crypto
account using the crypto symbol.
operationId: getCryptoSyncedBalanceBySymbol
parameters:
- name: id
in: path
description: Synced crypto account ID
required: true
schema:
type: integer
format: int32
- name: symbol
in: path
description: Crypto symbol within the synced account
required: true
schema:
type: string
minLength: 1
maxLength: 25
responses:
"200":
description: Synced crypto balance object
content:
application/json:
schema:
$ref: "#/components/schemas/cryptoSyncedBalance"
example:
name: ETH
balance: "12.004500000000000000"
symbol: eth
coingecko_id: ethereum
to_base: 28998.44
balance_as_of: "2026-02-25T14:25:00.000Z"
exchange_rate_as_of: "2026-02-25T14:20:00.000Z"
updated_at: "2026-02-25T14:25:01.000Z"
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
invalid id:
value:
message: Invalid Path Parameters
errors:
- errMsg: "Invalid value type for path parameter: 'id'. Expected 'number', received 'string'."
invalid symbol:
value:
message: Invalid Path Parameters
errors:
- errMsg: "Value for path parameter 'symbol' must not be empty."
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
account not found:
value:
message: Not Found
errors:
- errMsg: "There is no synced crypto account with the id: 99999999."
symbol not found:
value:
message: Not Found
errors:
- errMsg: "There is no synced crypto balance with symbol 'doge' for the crypto account with id: 33004."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/crypto/synced/{id}/refresh:
post:
tags:
- crypto-synced
summary: Refresh balances for a synced crypto account
description: Trigger a balance refresh for the specified synced crypto
account. Returns the refreshed synced crypto account.
operationId: refreshCryptoSynced
parameters:
- name: id
in: path
description: Synced crypto account ID
required: true
schema:
type: integer
format: int32
examples:
existing synced connection:
summary: Existing synced account ID
value: 33004
id not found:
summary: Example of an id that doesn't exist
value: 99999999
responses:
"200":
description: Refreshed synced crypto account
content:
application/json:
schema:
$ref: "#/components/schemas/syncedCryptoAccount"
example:
id: 33004
provider: coinbase
status: active
created_by_name: User 1
created_at: "2025-10-02T11:02:09.000Z"
display_name: Coinbase Main
balances:
- name: ETH
balance: "12.004500000000000000"
symbol: eth
coingecko_id: ethereum
to_base: 28998.44
balance_as_of: "2026-02-25T14:25:00.000Z"
exchange_rate_as_of: "2026-02-25T14:20:00.000Z"
updated_at: "2026-02-25T14:25:01.000Z"
- name: BTC
balance: "0.100020003000400050"
symbol: btc
coingecko_id: bitcoin
to_base: 6231.28
balance_as_of: "2026-02-25T14:25:00.000Z"
exchange_rate_as_of: "2026-02-25T14:20:00.000Z"
updated_at: "2026-02-25T14:25:01.000Z"
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no synced crypto account with the id: 99999999."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/balance_history:
get:
tags:
- balance_history
summary: Get balance history
description: >-
Retrieve historical balance entries.
Balance history is monthly. When `start_date` and `end_date` are both provided,
they must be first-of-month dates. `start_date` must not be in the future,
while `end_date` may be in the future. If one of `start_date` or `end_date`
is provided, the other is required. If neither is provided, all available
balance history is returned.
The response groups entries by source account. Each item in
`balance_history` contains a `source` object plus a `balances` array
containing one balance entry per month in the requested range, or all
stored entries when no range is provided.
Historical entries for accounts that have been deleted may still
be returned. These entries use `source.type: deleted` and include
`deleted_account_id`, archived display fields, and account metadata on the
`source` object.
operationId: getBalanceHistory
parameters:
- name: start_date
in: query
description: Optional start date for the requested history range in YYYY-MM-DD format. If set, `end_date` is also required. This must be the first day of a month and must not be in the future.
required: false
schema:
type: string
format: date
examples:
range start:
summary: Start date
value: "2026-01-01"
- name: end_date
in: query
description: Optional end date for the requested history range in YYYY-MM-DD format. If set, `start_date` is also required. This must be the first day of a month. For a single month, set this to the same first-of-month date as `start_date`.
required: false
schema:
type: string
format: date
examples:
range end:
summary: End date
value: "2026-03-01"
responses:
"200":
description: Historical balance entries for the requested date range
content:
application/json:
schema:
$ref: "#/components/schemas/balanceHistoryListResponseObject"
examples:
all account types:
value:
balance_history:
- source:
type: manual
manual_account_id: 119807
balances:
- id: 101
date: "2026-01-01"
balance: "41000.0000"
currency: usd
to_base: 41000
crypto_balance: null
- id: 102
date: "2026-02-01"
balance: "41211.8000"
currency: usd
to_base: 41211.8
crypto_balance: null
- source:
type: plaid
plaid_account_id: 119808
balances:
- id: 103
date: "2026-01-01"
balance: "5498.2800"
currency: usd
to_base: 5498.28
crypto_balance: null
- source:
type: crypto_manual
crypto_manual_id: 22001
symbol: btc
balances:
- id: 104
date: "2026-01-01"
balance: "53124.7200"
currency: usd
to_base: 53124.72
crypto_balance: "0.852341920145782301"
- source:
type: crypto_synced
crypto_synced_id: 33004
symbol: btc
balances:
- id: 105
date: "2026-01-01"
balance: "6231.2800"
currency: usd
to_base: 6231.28
crypto_balance: "0.100020003000400050"
- source:
type: deleted
deleted_account_id: 91
name: Savings
institution_name: Old Bank
display_name: Closed Savings
account_type: savings
subtype: savings
mask: "1234"
symbol: null
balances:
- id: 106
date: "2026-01-01"
balance: "1250.0000"
currency: usd
to_base: 1250
crypto_balance: null
manual account history:
value:
balance_history:
- source:
type: manual
manual_account_id: 119807
balances:
- id: 201
date: "2026-01-01"
balance: "41000.0000"
currency: usd
to_base: 41000
crypto_balance: null
- id: 202
date: "2026-02-01"
balance: "41211.8000"
currency: usd
to_base: 41211.8
crypto_balance: null
plaid account history:
value:
balance_history:
- source:
type: plaid
plaid_account_id: 119808
balances:
- id: 301
date: "2026-02-01"
balance: "5498.2800"
currency: usd
to_base: 5498.28
crypto_balance: null
synced crypto history:
value:
balance_history:
- source:
type: crypto_synced
crypto_synced_id: 33004
symbol: btc
balances:
- id: 401
date: "2026-02-01"
balance: "6231.2800"
currency: usd
to_base: 6231.28
crypto_balance: "0.100020003000400050"
deleted account history:
value:
balance_history:
- source:
type: deleted
deleted_account_id: 91
name: Savings
institution_name: Old Bank
display_name: Closed Savings
account_type: savings
subtype: savings
mask: "1234"
symbol: null
balances:
- id: 501
date: "2026-01-01"
balance: "1250.0000"
currency: usd
to_base: 1250
crypto_balance: null
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
missing paired date:
value:
message: Request Validation Failure
errors:
- errMsg: "`start_date` and `end_date` must either both be provided or both be omitted."
invalid range:
value:
message: Request Validation Failure
errors:
- errMsg: "`start_date` must be before or equal to `end_date`."
not first of month:
value:
message: Request Validation Failure
errors:
- errMsg: "`start_date` and `end_date` must both be the first day of a month."
future start date:
value:
message: Request Validation Failure
errors:
- errMsg: "`start_date` must not be in the future."
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/balance_history/{account_type}/{account_id}:
get:
tags:
- balance_history
summary: Get balance history for an account
description: >-
Retrieve historical balance entries for one manual, Plaid, manual crypto,
or deleted account. Crypto synced accounts require an additional `symbol` path parameter.
The `account_type` path parameter identifies the type of account and the
`account_id` path parameter identifies the specific id for that account type.
When `start_date` and `end_date` are both provided, they must be first-of-month
dates. `start_date` must not be in the future, while `end_date` may be in the future.
If one of `start_date` or `end_date` is provided, the other is required. If neither is
provided, all available history for the source is returned.
operationId: getBalanceHistoryForAccount
parameters:
- name: account_type
in: path
required: true
description: Source family to retrieve. Use `manual`, `plaid`, `crypto_manual`, or `deleted`.
schema:
type: string
enum: [manual, plaid, crypto_manual, deleted]
- name: account_id
in: path
required: true
description: Account or deleted-source identifier within the selected `account_type`.
schema:
type: integer
format: int32
- name: start_date
in: query
description: Optional start date for the requested history range in YYYY-MM-DD format. If set, `end_date` is also required. This must be the first day of a month and must not be in the future.
required: false
schema:
type: string
format: date
- name: end_date
in: query
description: Optional end date for the requested history range in YYYY-MM-DD format. If set, `start_date` is also required. This must be the first day of a month.
required: false
schema:
type: string
format: date
responses:
"200":
description: Historical balance entries for the requested source
content:
application/json:
schema:
$ref: "#/components/schemas/balanceHistoryListResponseObject"
examples:
manual account history:
value:
balance_history:
- source:
type: manual
manual_account_id: 119807
balances:
- id: 201
date: "2026-01-01"
balance: "41000.0000"
currency: usd
to_base: 41000
crypto_balance: null
- id: 202
date: "2026-02-01"
balance: "41211.8000"
currency: usd
to_base: 41211.8
crypto_balance: null
deleted account history:
value:
balance_history:
- source:
type: deleted
deleted_account_id: 91
name: Savings
institution_name: Old Bank
display_name: Closed Savings
account_type: savings
subtype: savings
mask: "1234"
symbol: null
balances:
- id: 501
date: "2026-01-01"
balance: "1250.0000"
currency: usd
to_base: 1250
crypto_balance: null
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
missing paired date:
value:
message: Request Validation Failure
errors:
- errMsg: "`start_date` and `end_date` must either both be provided or both be omitted."
invalid range:
value:
message: Request Validation Failure
errors:
- errMsg: "`start_date` must be before or equal to `end_date`."
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
manual not found:
value:
message: Not Found
errors:
- errMsg: "There is no manual account with the id: 99999999."
deleted not found:
value:
message: Not Found
errors:
- errMsg: "Deleted balance history source 99999999 was not found."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
put:
tags:
- balance_history
summary: Upsert balance history for an account
description: >-
Upsert one or more historical balance entries for a single manual, Plaid,
manual crypto, or deleted account. Crypto synced accounts require an additional `symbol` path parameter.
The `account_type` path parameter identifies the type of account and the
`account_id` path parameter identifies the specific id for that account type.
Submit one or more entries in the `balances` array. Each entry must specify
a `date` and `balance` value.
Balance history is monthly. Each entry's `date` must be the first day of
a month and must be in a past month.
`currency` may be provided for any balance entry. If omitted, it defaults
to the account currency for manual/Plaid accounts, or the user's primary
currency for crypto/deleted accounts.
`symbol` may only be set when `account_type` is `crypto_manual` or
`crypto_synced`. It is optional for `crypto_manual` accounts and tolerated
for `deleted` accounts.
`crypto_balance` may be provided for `crypto_manual`, `crypto_synced`, and
`deleted` accounts, and is invalid for `manual` or `plaid` accounts.
The response contains only the balance entries that were submitted in this request.
operationId: upsertBalanceHistoryForAccount
parameters:
- name: account_type
in: path
required: true
description: Source family to update. Use `manual`, `plaid`, `crypto_manual`, or `deleted`.
schema:
type: string
enum: [manual, plaid, crypto_manual, deleted]
- name: account_id
in: path
required: true
description: Account or deleted-source identifier within the selected `account_type`.
schema:
type: integer
format: int32
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/upsertBalanceHistoryRequestObject"
examples:
manual account bulk upsert:
value:
balances:
- date: "2026-03-01"
balance: "41500.0000"
- date: "2026-04-01"
balance: "41625.5000"
crypto manual balance with symbol:
value:
balances:
- date: "2026-03-01"
balance: "56011.1200"
symbol: btc
crypto_balance: "0.852341920145782301"
deleted account bulk upsert:
value:
balances:
- date: "2026-03-01"
symbol: btc
crypto_balance: "0.020000000000000000"
currency: usd
balance: "1255"
get-shaped balance entry input:
value:
balances:
- id: 601
date: "2026-03-01"
balance: "41500.0000"
currency: usd
to_base: 41500
crypto_balance: null
responses:
"200":
description: Returns the modified balance entries only. Other historical
entries for the account are omitted from `balances`.
content:
application/json:
schema:
$ref: "#/components/schemas/balanceHistoryAccountObject"
examples:
manual account bulk upsert:
summary: Two upserted rows returned (not full account history)
value:
source:
type: manual
manual_account_id: 119807
balances:
- id: 601
date: "2026-03-01"
balance: "41500.0000"
currency: usd
to_base: 41500
crypto_balance: null
- id: 602
date: "2026-04-01"
balance: "41625.5000"
currency: usd
to_base: 41625.5
crypto_balance: null
crypto manual balance with symbol:
summary: Single upserted row returned
value:
source:
type: crypto_manual
crypto_manual_id: 22001
symbol: btc
balances:
- id: 603
date: "2026-03-01"
balance: "56011.1200"
currency: usd
to_base: 56011.12
crypto_balance: "0.852341920145782301"
deleted account bulk upsert:
summary: Single upserted row returned
value:
source:
type: deleted
deleted_account_id: 91
name: Savings
institution_name: Old Bank
display_name: Closed Savings
account_type: savings
subtype: savings
mask: "1234"
symbol: btc
balances:
- id: 504
date: "2026-03-01"
balance: "1255"
currency: usd
to_base: 1255
crypto_balance: "0.020000000000000000"
"400":
description: Bad Request. The entire request is rejected if any row in
`balances` fails validation; no rows are updated.
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
missing balances:
value:
message: Invalid Request Body
errors:
- errMsg: "Missing required property 'balances' in request body."
empty balances array:
value:
message: Invalid Request Body
errors:
- errMsg: "Invalid value for property 'balances'. Array must contain at least 1 element(s)"
invalid property:
value:
message: Invalid Request Body
errors:
- errMsg: "Invalid property 'foo' in request body."
invalid date:
value:
message: Request Validation Failure
errors:
- errMsg: "`date` must be the first day of a month."
request_balances_index: 0
code: VALIDATION_ERROR
future date:
value:
message: Request Validation Failure
errors:
- errMsg: "`date` must be in a past month."
request_balances_index: 1
crypto balance not allowed:
value:
message: Request Validation Failure
errors:
- errMsg: "`crypto_balance` may only be set when `account_type` is `crypto_manual`, `crypto_synced`, or `deleted`."
request_balances_index: 0
invalid row in bulk request:
value:
message: Request Validation Failure
errors:
- errMsg: "`symbol` may only be set when `account_type` is `crypto_manual` or `crypto_synced`."
request_balances_index: 1
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no manual account with the id: 99999999."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
delete:
tags:
- balance_history
summary: Delete all balance history for an account
description: >-
Delete all historical balance entries for a single manual, Plaid,
manual crypto, or deleted account. Crypto synced accounts require an additional `symbol` path parameter.
operationId: deleteBalanceHistoryForAccount
parameters:
- name: account_type
in: path
required: true
description: Source family to delete. Use `manual`, `plaid`, `crypto_manual`, or `deleted`.
schema:
type: string
enum: [manual, plaid, crypto_manual, deleted]
- name: account_id
in: path
required: true
description: Account or deleted-source identifier within the selected `account_type`.
schema:
type: integer
format: int32
responses:
"204":
description: All history for the account/source was deleted
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
source not found:
value:
message: Not Found
errors:
- errMsg: "There is no manual account with the id: 99999999."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/balance_history/crypto_synced/{account_id}/{symbol}:
get:
tags:
- balance_history
summary: Get balance history for a synced crypto symbol
description: >-
Retrieve historical balance entries for a single synced crypto symbol stream.
Use the `crypto_synced` account id together with a `symbol` path parameter
to select one balance stream within that synced crypto account.
When `start_date` and `end_date` are both provided, they must be first-of-month
dates. `start_date` must not be in the future, while `end_date` may be in the future.
If one of `start_date` or `end_date` is provided, the other is required. If neither is
provided, all available history for the symbol stream is returned.
operationId: getBalanceHistoryForCryptoSynced
parameters:
- name: account_id
in: path
required: true
description: Synced crypto account identifier.
schema:
type: integer
format: int32
- name: symbol
in: path
required: true
description: Crypto symbol identifying one balance stream within the synced crypto account.
schema:
type: string
minLength: 1
maxLength: 25
- name: start_date
in: query
description: Optional start date for the requested history range in YYYY-MM-DD format. If set, `end_date` is also required. This must be the first day of a month and must not be in the future.
required: false
schema:
type: string
format: date
- name: end_date
in: query
description: Optional end date for the requested history range in YYYY-MM-DD format. If set, `start_date` is also required. This must be the first day of a month.
required: false
schema:
type: string
format: date
responses:
"200":
description: Historical balance entries for the synced crypto symbol stream
content:
application/json:
schema:
$ref: "#/components/schemas/balanceHistoryListResponseObject"
example:
balance_history:
- source:
type: crypto_synced
crypto_synced_id: 33004
symbol: btc
balances:
- id: 401
date: "2026-02-01"
balance: "6231.2800"
currency: usd
to_base: 6231.28
crypto_balance: "0.100020003000400050"
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
missing paired date:
value:
message: Request Validation Failure
errors:
- errMsg: "`start_date` and `end_date` must either both be provided or both be omitted."
invalid range:
value:
message: Request Validation Failure
errors:
- errMsg: "`start_date` must be before or equal to `end_date`."
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
source not found:
value:
message: Not Found
errors:
- errMsg: "There is no synced crypto account with the id: 99999999."
symbol not found:
value:
message: Not Found
errors:
- errMsg: "There is no balance history for symbol 'doge' on this account."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
put:
tags:
- balance_history
summary: Upsert balance history for a synced crypto symbol
description: >-
Upsert one or more historical balance entries for a single synced crypto
symbol stream.
The path identifies both the synced crypto account and the symbol being updated.
Submit one or more entries in the `balances` array. Each entry must specify
a `date` and `balance` value.
Balance history is monthly. Each entry's `date` must be the first day of
a month and must be in a past month.
The request body may include an optional `symbol` on each balance entry. If
provided, it must match the `symbol` path parameter. Omit `symbol` to use
the path value.
`currency` may be provided for any balance entry. If omitted, it defaults
to the user's primary currency for synced crypto balances.
`crypto_balance` may be provided for synced crypto balances.
The response contains only the balance entries that were submitted in this request.
operationId: upsertBalanceHistoryForCryptoSynced
parameters:
- name: account_id
in: path
required: true
description: Synced crypto account identifier to update.
schema:
type: integer
format: int32
- name: symbol
in: path
required: true
description: Crypto symbol identifying one balance stream within the synced crypto account.
schema:
type: string
minLength: 1
maxLength: 25
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/upsertBalanceHistoryRequestObject"
examples:
synced crypto bulk upsert:
value:
balances:
- date: "2026-03-01"
balance: "6400.0000"
crypto_balance: "0.100020003000400050"
- date: "2026-04-01"
balance: "6500.0000"
crypto_balance: "0.100020003000400050"
responses:
"200":
description: Returns the modified balance entries only. Other historical
entries for the symbol stream are omitted from `balances`.
content:
application/json:
schema:
$ref: "#/components/schemas/balanceHistoryAccountObject"
examples:
synced crypto bulk upsert:
summary: Two upserted rows returned (not full symbol history)
value:
source:
type: crypto_synced
crypto_synced_id: 33004
symbol: btc
balances:
- id: 604
date: "2026-03-01"
balance: "6400.0000"
currency: usd
to_base: 6400
crypto_balance: "0.100020003000400050"
- id: 605
date: "2026-04-01"
balance: "6500.0000"
currency: usd
to_base: 6500
crypto_balance: "0.100020003000400050"
"400":
description: Bad Request. The entire request is rejected if any row in
`balances` fails validation; no rows are updated.
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
missing balances:
value:
message: Invalid Request Body
errors:
- errMsg: "Missing required property 'balances' in request body."
empty balances array:
value:
message: Invalid Request Body
errors:
- errMsg: "Invalid value for property 'balances'. Array must contain at least 1 element(s)"
invalid date:
value:
message: Request Validation Failure
errors:
- errMsg: "`date` must be the first day of a month."
request_balances_index: 0
future date:
value:
message: Request Validation Failure
errors:
- errMsg: "`date` must be in a past month."
request_balances_index: 1
symbol mismatch:
value:
message: Request Validation Failure
errors:
- errMsg: "`symbol` in request body (doge) does not match the path symbol (eth)."
request_balances_index: 0
invalid row in bulk request:
value:
message: Request Validation Failure
errors:
- errMsg: "`balance` must be a valid numeric string or number."
request_balances_index: 1
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
source not found:
value:
message: Not Found
errors:
- errMsg: "There is no synced crypto account with the id: 99999999."
symbol not found:
value:
message: Not Found
errors:
- errMsg: "There is no balance history for symbol 'doge' on this account."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
delete:
tags:
- balance_history
summary: Delete all balance history for a synced crypto symbol
description: >-
Delete all historical balance entries for a single synced crypto symbol stream.
The path identifies both the synced crypto account and the symbol whose
history should be deleted.
operationId: deleteBalanceHistoryForCryptoSynced
parameters:
- name: account_id
in: path
required: true
description: Synced crypto account identifier.
schema:
type: integer
format: int32
- name: symbol
in: path
required: true
description: Crypto symbol identifying one balance stream within the synced crypto account.
schema:
type: string
minLength: 1
maxLength: 25
responses:
"204":
description: All history for the synced crypto symbol stream was deleted
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no balance history for symbol 'doge' on this account."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/balance_history/entries/{id}:
delete:
tags:
- balance_history
summary: Delete a balance history entry
description: >-
Delete a single monthly balance history entry by its id.
operationId: deleteBalanceHistoryEntry
parameters:
- name: id
in: path
required: true
description: Balance history row identifier to delete.
schema:
type: integer
format: int32
responses:
"204":
description: The balance history entry was deleted
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Request Validation Failure
errors:
- errMsg: "Invalid value type for path parameter: 'id'. Expected 'number', received 'string'."
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no balance history entry with the id: 99999999."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/balance_history/deleted/{account_id}/details:
put:
tags:
- balance_history
summary: Update details for a deleted account
description: >-
Update archived metadata for a deleted balance history source.
Pass the `deleted` source id returned on `source.deleted_account_id`.
This endpoint updates the stored deleted-source metadata used for all
historical entries associated with that deleted source.
operationId: updateBalanceHistoryDetails
parameters:
- name: account_id
in: path
required: true
description: Deleted account history source identifier to update.
schema:
type: integer
format: int32
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/updateBalanceHistoryDetailsRequestObject"
examples:
update deleted source details:
value:
name: Savings
institution_name: Old Bank
display_name: Old Savings Account
account_type: savings
subtype: savings
mask: "1234"
responses:
"200":
description: Updated deleted source details
content:
application/json:
schema:
$ref: "#/components/schemas/updateBalanceHistoryDetailsResponseObject"
example:
name: Savings
institution_name: Old Bank
display_name: Old Savings Account
account_type: savings
subtype: savings
mask: "1234"
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Invalid Request Body
errors:
- errMsg: "At least one property must be provided: name, institution_name, display_name, account_type, subtype, mask."
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "Deleted balance history source 99999999 was not found."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/manual_accounts:
get:
tags:
- manual_accounts
summary: Get all manual accounts
description: Retrieve a list of all manually-managed accounts associated
with the user's account.
operationId: getAllManualAccounts
responses:
"200":
description: A list of manual accounts
content:
application/json:
schema:
type: object
properties:
manual_accounts:
type: array
items:
$ref: "#/components/schemas/manualAccountObject"
example:
manual_accounts:
- id: 119807
name: Individual Brokerage
institution_name: Fidelity
display_name: null
type: investment
subtype: brokerage
balance: "41211.8000"
currency: usd
to_base: 41211.8
balance_as_of: "2025-06-25T17:00:04.000Z"
status: active
closed_on: null
external_id: null
exclude_from_transactions: false
created_by_name: User 1
created_at: "2025-06-25T17:00:04.414Z"
updated_at: "2025-06-26T19:03:38.312Z"
- id: 119909
name: Euro Travel Card
institution_name: WeBank
display_name: null
type: credit
subtype: credit card
balance: "1004.8000"
currency: usd
to_base: 1004.8
balance_as_of: "2023-06-25T17:00:04.000Z"
status: active
closed_on: null
external_id: null
exclude_from_transactions: false
created_by_name: User 1
created_at: "2025-06-25T17:00:04.414Z"
updated_at: "2025-06-26T19:03:38.312Z"
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Request Validation Failure
errors:
- errMsg: must NOT have additional properties
instancePath: /query
schemaPath: "#/properties/query/additionalProperties"
keyword: additionalProperties
params:
additionalProperty: foo
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
post:
tags:
- manual_accounts
summary: Create a manual account
description: Create a new manually-managed account.
operationId: createManualAccount
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/createManualAccountRequestObject"
examples:
minimum request body:
summary: Minimum required fields for creating a manual account
value:
name: API created Account
type: cash
balance: "100"
full example:
summary: Full example with all fields
value:
name: API created loan
type: vehicle
subtype: loan
display_name: Car loan
balance: "9999.99"
balance_as_of: "2024-10-12"
closed_on: null
currency: usd
institution_name: Bank of America
exclude_from_transactions: false
display_name not unique:
summary: Explicit display_name not unique
value:
name: API created card
type: credit
display_name: WeBank Euro Travel Card
balance: "1004.8000"
implicit display_name not unique:
summary: Derived display_name not unique
value:
name: Individual Brokerage
type: investment
institution_name: Fidelity
balance: "41211.8000"
responses:
"201":
description: Successfully created manual account
content:
application/json:
schema:
$ref: "#/components/schemas/manualAccountObject"
examples:
minimum request response:
value:
id: 119999
name: API created Account
institution_name: null
display_name: null
type: cash
subtype: null
balance: "100"
currency: usd
to_base: 100
balance_as_of: "2024-10-06T18:55:08.599Z"
status: active
closed_on: null
external_id: null
exclude_from_transactions: false
created_by_name: User 1
created_at: "2024-10-06T18:55:08.599Z"
updated_at: "2024-10-06T18:55:08.599Z"
complete request response:
value:
id: 119999
name: API created loan
institution_name: Bank of America
display_name: Car loan
type: vehicle
subtype: loan
balance: "9999.99"
currency: usd
to_base: 9999.99
balance_as_of: "2024-10-06T18:55:08.599Z"
status: active
closed_on: null
external_id: null
exclude_from_transactions: false
created_by_name: User 1
created_at: "2024-10-06T18:57:12.029Z"
updated_at: "2024-10-06T18:57:12.029Z"
"400":
description: Invalid request body
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
missing required properties:
value:
message: Request Validation Failure
errors:
- errMsg: "Missing required property 'name' in request body."
- errMsg: "Missing required property 'type' in request body."
- errMsg: "Missing required property 'balance' in request body."
explicit display_name not unique:
value:
message: Request Validation Failure
errors:
- errMsg: "A manual account with the same display_name: 'WeBank Travel Card' already exists."
existing_manual_account_id: 219909
requested_display_name: "WeBank Travel Card"
existing_display_name: "WeBank Travel Card"
existing_name: "Euro Travel Card"
requested_name: "API created card"
implicit display_name not unique:
value:
message: Request Validation Failure
errors:
- errMsg: "A manual account with the same implicit display_name derived from name: 'Individual Brokerage' and institution_name: 'Fidelity' already exists."
existing_manual_account_id: 219807
requested_name: Individual Brokerage
existing_name: Individual Brokerage
requested_institution_name: Fidelity
existing_institution_name: Fidelity
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/manual_accounts/{id}:
get:
tags:
- manual_accounts
summary: Get a single manual account
description: Retrieve the details of the manual account with the specified
ID.
operationId: getManualAccountById
parameters:
- name: id
in: path
description: ID of the manual account to retrieve
required: true
schema:
type: integer
format: int32
examples:
basic manual account:
summary: Basic manual account by id request
value: 119807
id not found:
summary: Example of an id that doesn't exist
value: 9999999999999
responses:
"200":
description: Manual Account Object with the requested account
content:
application/json:
schema:
$ref: "#/components/schemas/manualAccountObject"
example:
id: 119807
name: Individual Brokerage
institution_name: Fidelity
display_name: null
type: investment
subtype: brokerage
balance: "41211.8000"
currency: usd
to_base: 41211.8
balance_as_of: "2025-06-25T17:00:04.000Z"
status: active
closed_on: null
external_id: null
exclude_from_transactions: false
created_by_name: User 1
created_at: "2025-06-25T17:00:04.414Z"
updated_at: "2025-06-26T19:03:38.312Z"
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
invalid account id type:
value:
message: Invalid Path Parameters
errors:
- errMsg: "Invalid value type for path parameter: 'id'. Expected 'number', received 'string'."
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: There is no manual account with the id:'9999999999999'`
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
put:
tags:
- manual_accounts
summary: Update an existing manual account
description: >-
Modifies the properties of an existing manual account.
You may submit the response from a `GET /manual_accounts/{id}` as the request body, however only certain
properties can be updated using this API. The following system set properties are
accepted in the request body but their values will be ignored: `id`, `to_base`, `created_at`, and `updated_at`.
It is also possible to provide only the properties to be updated in the
request body, as long as the request includes at least one of the
properties that is not listed above. For example a request body that contains only a `name` property is valid.
operationId: updateManualAccount
parameters:
- name: id
in: path
description: ID of the manual account to update
required: true
schema:
type: integer
format: int32
examples:
category:
summary: Example of a manual account's id
value: 119807
not found:
summary: Example of a manual account ID that does not exist
value: 999999999
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/updateManualAccountRequestObject"
examples:
minimum request body:
summary: type change
value:
type: credit
close account:
summary: close and exclude
value:
closed_on: "2024-10-15"
exclude_from_transactions: true
use get request:
summary: Only display name has changed
value:
id: 119909
name: Euro Travel Card
type: credit
subtype: credit card
display_name: New Display Name
balance: "1004.8000"
balance_as_of: "2023-06-25T17:00:04.000Z"
closed_on: null
currency: usd
institution_name: WeBank
exclude_from_transactions: false
created_at: "2025-06-25T17:00:04.414Z"
updated_at: "2025-06-26T19:03:38.312Z"
responses:
"200":
description: Manual Account updated successfully
content:
application/json:
schema:
$ref: "#/components/schemas/manualAccountObject"
examples:
type changed to credit:
value:
id: 119807
name: Individual Brokerage
institution_name: Fidelity
display_name: null
type: investment
subtype: brokerage
balance: "41211.8000"
currency: usd
to_base: 41211.8
balance_as_of: "2025-06-25T17:00:04.000Z"
status: active
closed_on: null
external_id: null
exclude_from_transactions: false
created_by_name: User 1
created_at: "2025-06-25T17:00:04.414Z"
updated_at: "2025-06-26T19:03:38.312Z"
closed account:
value:
id: 119807
name: Individual Brokerage
institution_name: Fidelity
display_name: null
type: investment
subtype: brokerage
balance: "41211.8000"
currency: usd
to_base: 41211.8
balance_as_of: "2025-06-25T17:00:04.000Z"
status: closed
closed_on: "2024-10-06"
external_id: null
exclude_from_transactions: true
created_by_name: User 1
created_at: "2025-06-25T17:00:04.414Z"
updated_at: "2024-10-06T19:03:09.506Z"
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
missing required properties:
value:
message: Invalid Request Body
errors:
- errMsg: "A request to update a manual account must include at least one of the
following properties: name, type, subtype, display_name,
balance, balance_as_of, closed_on, currency,
institution_name, exclude_from_transactions"
duplicate display_name:
value:
message: Request Validation Failure
errors:
- errMsg: "A manual account with the same display_name: 'WeBank Travel Card' already exists."
existing_manual_account_id: 219909
requested_display_name: "WeBank Travel Card"
existing_display_name: "WeBank Travel Card"
existing_name: "Euro Travel Card"
requested_name: "API created card"
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no manual account with the id: 543210."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
delete:
tags:
- manual_accounts
summary: Delete a manual account
description: Deletes the single manual account with the ID specified on
the path. If any transactions exist with the `manual_account_id`
property set to this account's ID they will appear with a warning when
displayed in the web view.
operationId: deleteManualAccount
parameters:
- in: path
name: id
description: ID of the manual account to delete
required: true
schema:
type: integer
format: int32
examples:
delete manual account:
summary: Account ID to delete
value: 119807
id not found:
summary: Example of an id that doesn't exist
value: 543210
- in: query
name: delete_items
description: When set to true will also delete any transactions,
rules, and recurring items associated with this account. Use this
option with caution, it is irreversible!
required: false
schema:
type: boolean
default: false
- in: query
name: delete_balance_history
description: When set to true will delete any balance history
associated with this account.
required: false
schema:
type: boolean
default: false
responses:
"204":
description: No Content
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no manual account with the id: 543210."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/plaid_accounts:
get:
tags:
- plaid_accounts
summary: Get all accounts synced via Plaid
description: Retrieve a list of all synced accounts associated with the
user's account.
operationId: getAllPlaidAccounts
responses:
"200":
description: A list of accounts synced via Plaid
content:
application/json:
schema:
type: object
properties:
plaid_accounts:
type: array
items:
$ref: "#/components/schemas/plaidAccountObject"
example:
plaid_accounts:
- id: 119804
plaid_item_id: "aB2cD3eF4gH5iJ6kL7mN8oP9qR0sT1uV2wX3yZ4"
date_linked: "2020-01-28"
linked_by_name: User 1
name: 401k
display_name: ""
type: brokerage
subtype: 401k
mask: "7468"
institution_name: Vanguard
status: inactive
allow_transaction_modifications: false
limit: null
balance: "12345.6700"
currency: usd
to_base: 12345.67
balance_last_update: "2025-01-27T01:38:11.862Z"
import_start_date: "2023-01-01"
last_import: "2025-01-24T12:57:09.190Z"
last_fetch: "2025-01-28T01:38:11.862Z"
plaid_last_successful_update: "2025-01-27T01:38:11.862Z"
- id: 119805
plaid_item_id: "xY9zW8vU7tS6rQ5pO4nM3lK2jI1hG0fE9dC8bA7"
date_linked: "2020-01-28"
linked_by_name: User 1
name: Freedom
display_name: Penny's Visa
type: credit
subtype: credit card
mask: "1973"
institution_name: Chase
status: active
allow_transaction_modifications: true
limit: 15000
balance: "0.0000"
currency: usd
to_base: 0
balance_last_update: "2025-01-27T01:38:07.460Z"
import_start_date: "2023-01-01"
last_import: "2025-01-24T12:57:03.250Z"
last_fetch: "2025-01-28T01:38:11.862Z"
plaid_last_successful_update: "2025-01-27T01:38:11.862Z"
- id: 119807
plaid_item_id: "mK8nL9oP0qR1sT2uV3wX4yZ5aB6cD7eF8gH9iJ0"
date_linked: "2020-01-28"
linked_by_name: User 1
name: Checking
display_name: Penny's Checking
type: cash
subtype: checking
mask: "2046"
institution_name: Western Bank
status: active
allow_transaction_modifications: true
limit: null
balance: "5498.2800"
currency: usd
to_base: 5498.28
balance_last_update: "2025-01-27T01:38:07.460Z"
import_start_date: "2023-01-01"
last_import: "2025-01-24T12:57:03.250Z"
last_fetch: "2025-01-28T01:38:11.862Z"
plaid_last_successful_update: "2025-01-27T01:38:11.862Z"
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Request Validation Failure
errors:
- errMsg: must NOT have additional properties
instancePath: /query
schemaPath: "#/properties/query/additionalProperties"
keyword: additionalProperties
params:
additionalProperty: foo
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/plaid_accounts/{id}:
get:
tags:
- plaid_accounts
summary: Get a single account that is synced via Plaid
description: Retrieve the details of the plaid account with the specified
ID.
operationId: getPlaidAccountById
parameters:
- name: id
in: path
description: ID of the plaid account to retrieve
required: true
schema:
type: integer
format: int32
examples:
basic manual account:
summary: Basic plaid account by id request
value: 119805
id not found:
summary: Example of an id that doesn't exist
value: 9999999999999
responses:
"200":
description: Plaid Account Object with the requested account.
content:
application/json:
schema:
$ref: "#/components/schemas/plaidAccountObject"
example:
id: 119805
plaid_item_id: "xY9zW8vU7tS6rQ5pO4nM3lK2jI1hG0fE9dC8bA7"
date_linked: "2020-01-28"
linked_by_name: User 1
name: Freedom
display_name: Penny's Visa
type: credit
subtype: credit card
mask: "1973"
institution_name: Chase
status: active
allow_transaction_modifications: true
limit: 15000
balance: "0.0000"
currency: usd
to_base: 0
balance_last_update: "2025-01-27T01:38:07.460Z"
import_start_date: "2023-01-01"
last_import: "2025-01-24T12:57:03.250Z"
last_fetch: "2025-01-28T01:38:11.862Z"
plaid_last_successful_update: "2025-01-27T01:38:11.862Z"
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Request Validation Failure
errors:
- errMsg: must be integer
instancePath: /path/id
schemaPath: "#/properties/path/properties/ids/items/type"
keyword: type
params:
type: integer
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no plaid account with the id: 9999999999999"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/plaid_accounts/fetch:
post:
tags:
- plaid_accounts
summary: Trigger Fetch from Plaid
description: >-
Use this endpoint to trigger a fetch for latest data from Plaid.
Eligible accounts are those who last_fetch value is over 1 minute ago.
(Although the limit is every minute, please use this endpoint
sparingly!) Successive calls to this endpoint under a minute after the
first will return a 425 TOO EARLY response.
Successful calls will return a 202 ACCEPTED response. Note that fetching
from Plaid is a background job. This endpoint simply queues up the job.
You may track the `plaid_last_successful_update`, `last_fetch` and
`last_import` properties to verify the results of the fetch. The `last
fetch` property is updated when Plaid accepts a request to fetch data.
The `plaid_last_successful_update`is updated when it successfully
contacts the associated financial institution. The `last_import` field
is updated only when new transactions have been imported.
operationId: triggerPlaidAccountFetch
parameters:
- name: start_date
in: query
schema:
type: string
format: date
description: Indicates the beginning of the time period to fetch
transactions for. If omitted, the most recent transactions will be
returned.
Required if end_date exists.
- name: end_date
in: query
schema:
type: string
format: date
description: "Indicates the end of the time period to fetch
transactions for. Required if start_date exists. "
- name: id
in: query
description: Specific ID of a plaid account to fetch. If not set the
endpoint will trigger a fetch for all eligible accounts.
schema:
type: integer
format: int32
examples:
basic manual account:
summary: Basic manual account by id request
value: 119807
id not found:
summary: Example of an id that doesn't exist
value: 9999999999999
responses:
"202":
description: A 202 ACCEPTED status is returned if Plaid acknowledged
the fetch request. This indicates that it is possible to
subsequently query the `GET /plaid_accounts` endpoint to determine
if the request was successful (`plaid_last_successful_update` is
more recent than `last_fetch`), or if new transactions were synced
(`last_import` is more recent than `last_fetch`).
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
missing end_date:
value:
message: Invalid Request Parameters
errors:
- errMsg: "Both 'start_date' and 'end_date' must be specified."
invalid id type:
value:
message: Request Validation Failure
errors:
- errMsg: must be integer
instancePath: /path/id
schemaPath: "#/properties/path/properties/ids/items/type"
keyword: type
params:
type: integer
"401":
$ref: "#/components/responses/unauthorizedToken"
"425":
description: Too Early
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Too Early
errors:
- errMsg: "Please wait at least 60 seconds between fetch requests."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/transactions:
get:
tags:
- transactions (bulk)
summary: Get all transactions
description: Retrieve a list of all transactions associated with a user's
account.
If called with no parameters, this endpoint will return the
most recent transactions, up to the specified `limit`.
operationId: getAllTransactions
parameters:
- name: start_date
in: query
schema:
type: string
format: date
description: Indicates the beginning of the time period to fetch
transactions for. If omitted, the most recent transactions will be
returned. See `limit`. Required if end_date exists.
- name: end_date
in: query
schema:
type: string
format: date
description: "Indicates the end of the time period to fetch
transactions for. Required if start_date exists. "
- name: created_since
in: query
schema:
oneOf:
- type: string
format: date
- type: string
format: date-time
description: Filter transactions to those created after the specified
timestamp. Accepts either a date (YYYY-MM-DD) or ISO 8601 datetime
string. Date-only values are interpreted as midnight UTC
(00:00:00Z).
- name: updated_since
in: query
schema:
oneOf:
- type: string
format: date
- type: string
format: date-time
description: Filter transactions to those updated after the specified
timestamp. Accepts either a date (YYYY-MM-DD) or ISO 8601 datetime
string. Date-only values are interpreted as midnight UTC
(00:00:00Z).
- name: manual_account_id
in: query
schema:
type: integer
format: int32
description: Filter transactions to those associated with specified
manual account ID or set this to 0 to omit any transactions from
manual accounts. Setting both this and `plaid_account_id` to 0 will
return transactions with no account. These are listed as "Cash
Transactions" in the Lunch Money app.
Note that transaction
groups are not associated with any account. If you want the response
to include transactions from transaction groups, set the
`include_group_children` query parameter to `true` when filtering by
manual accounts.
examples:
euro travel card:
value: 219909
no manual accounts:
value: 0
- name: plaid_account_id
in: query
schema:
type: integer
format: int32
description: Filter transactions to those associated with specified
plaid account ID or set this to 0 to omit any transactions from
plaid accounts. Setting both this and `manual_account_id` to 0 will
return transactions with no account. These are listed as "Cash
Transactions" in the Lunch Money app.
Note that transaction
groups are not associated with any account. If you want the response
to include transactions from transaction groups, set the
`include_group_children` query parameter to `true` when filtering by
plaid accounts.
examples:
brokerage account:
value: 119807
no plaid accounts:
value: 0
- name: recurring_id
in: query
schema:
type: integer
format: int32
description: >
Filter transactions to those associated with the specified recurring
item ID.
examples:
paychecks:
value: 994069
rent:
value: 994079
- name: category_id
in: query
schema:
type: integer
format: int32
description: Filter transactions to those associated with the
specified category ID. Will also match category groups. Set this to
0 to return only uncategorized transactions.
examples:
rent:
value: 83
food category group:
value: 84
- name: tag_id
in: query
schema:
type: integer
format: int32
description: Filter transactions to those that have the specified tag
ID
- name: is_group_parent
in: query
schema:
type: boolean
description: Filter by group (returns only transaction groups if
`true`)
- name: status
in: query
schema:
type: string
enum:
- reviewed
- unreviewed
- delete_pending
description: "Filter transactions to those with the specified
status:
-
`reviewed`: Only user reviewed transactions or those that were
automatically marked as reviewed due to reviewed recurring_item
logic
- `unreviewed`: Only transactions that need to be
reviewed
- `delete_pending`: Only transactions that require
manual intervention because the plaid account deleted this
transaction after it was updated by the user."
examples:
needs review:
value: unreviewed
needs deletion:
value: delete_pending
- name: is_pending
in: query
schema:
type: boolean
description: >
Filter transactions by pending status. Set to `true` to return only pending transactions,
or `false` to return only non-pending transactions. When this parameter is set, it takes
precedence over `include_pending`. Note: Pending transactions always have a status of
`unreviewed`, so when setting this parameter to `true`, either omit the `status` parameter
or set it to `unreviewed`.
examples:
only pending:
value: true
exclude pending:
value: false
- name: include_pending
in: query
schema:
type: boolean
default: false
description: >
By default, pending transactions are excluded from results. Set to `true` to include
imported transactions with a pending status in the results. This query param is ignored
if the `is_pending` query param is also set.
- name: include_metadata
in: query
schema:
type: boolean
default: false
description: By default, custom and plaid metadata are not included in
the response. Set to true if you'd like the returned transaction
objects to include any metadata associated with the transactions.
- name: include_split_parents
in: query
schema:
type: boolean
default: false
description: By default, transactions that were split into multiple
transactions are not included in the response. Set to true if you'd
like the returned transaction objects to include transactions that
were split into multiple transactions. Use with caution, as this
data is normally not exposed after the split transactions are
created.
- name: include_group_children
in: query
schema:
type: boolean
default: false
description: By default, individual transactions that joined into a
transaction group are not included in the response. Set to true if
you'd like the returned transactions objects to include any
transactions that joined into a transaction group.
- name: include_children
in: query
schema:
type: boolean
default: false
description: By default, the `children` property is not included in
the response. Set to true if you'd like the children property to be
populated with the transactions that make up a transaction group,
or, if the `include_split_parents` query param is also set, the
transactions that were split from a parent transaction.
- name: include_files
in: query
schema:
type: boolean
default: false
description: By default, the `files` property is not included in the
response. Set to true if you'd like the responses to include a list
of objects that describe any files attached to the transactions.
- name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 2000
default: 1000
description: Sets the maximum number of transactions to return. If
more match the filter criteria, the response will include a
`has_more` attribute set to `true`. See
[Pagination](https://lm-v2-api-next-a7fabcab8e9a.herokuapp.com/v2/pagination)
- name: offset
in: query
schema:
type: integer
description: Sets the offset for the records returned. This is
typically set automatically in the header. See
[Pagination](https://lm-v2-api-next-a7fabcab8e9a.herokuapp.com/v2/pagination)
responses:
"200":
description: Returns an array of transactions.
The `has_more`
property is set to `true` if more transactions are available. See
[Pagination](https://lm-v2-api-next-a7fabcab8e9a.herokuapp.com/v2/pagination)
content:
application/json:
schema:
properties:
transactions:
items:
$ref: "#/components/schemas/transactionObject"
type: array
has_more:
type: boolean
description: Set to true if more transactions are available
error:
type: string
required:
- transactions
- has_more
examples:
default response:
summary: Default response
value:
transactions:
- id: 2112150655
date: "2024-07-28"
amount: "1250.8400"
currency: usd
to_base: 1250.84
recurring_id: 994069
payee: Paycheck
original_name: DIRECT DEPOSIT PAYROLL
category_id: 88
notes: null
status: reviewed
is_pending: false
created_at: "2024-07-28T17:00:06.192Z"
updated_at: "2024-07-28T17:00:06.733Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: 119806
tag_ids:
- 94317
source: plaid
external_id: null
- id: 2112150655
date: "2024-07-24"
amount: "21.9800"
currency: usd
to_base: 21.98
recurring_id: null
payee: Noodle House
original_name: NOODLE HOUSE RESTAURANT #5678
category_id: null
notes: null
status: unreviewed
is_pending: false
created_at: "2024-07-24T17:00:06.192Z"
updated_at: "2024-07-24T17:00:06.192Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: 119805
tag_ids:
- 94317
source: plaid
external_id: null
- id: 2112150653
date: "2024-07-22"
amount: "-847.2200"
currency: usd
to_base: -847.22
recurring_id: null
payee: Credit Card Payment
original_name: CHASE CREDIT CARD PAYMENT
category_id: 82
is_pending: false
status: reviewed
notes: null
created_at: "2024-07-22T17:00:06.192Z"
updated_at: "2024-07-22T17:00:06.733Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: 119804
tag_ids: []
source: plaid
external_id: null
- id: 2112150651
date: "2024-07-22"
amount: "250.0000"
currency: usd
to_base: 250
recurring_id: null
payee: Fidelity
original_name: Fidelity
category_id: 82
notes: Transfer from Checking to Fidelity
status: reviewed
is_pending: false
created_at: "2024-07-22T17:00:06.192Z"
updated_at: "2024-07-22T17:00:06.733Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: 119807
plaid_account_id: null
tag_ids: []
source: csv
external_id: null
has_more: false
recurring paychecks:
summary: recurring paychecks
value:
transactions:
- id: 2112150655
date: "2024-07-28"
amount: "1250.8400"
currency: usd
to_base: 1250.84
recurring_id: 994069
payee: Paycheck
original_name: DIRECT DEPOSIT PAYROLL
category_id: 88
notes: null
status: reviewed
is_pending: false
created_at: "2024-07-28T17:00:06.192Z"
updated_at: "2024-07-28T17:00:06.733Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: 119806
tag_ids:
- 94317
source: plaid
external_id: null
- id: 2112150653
date: "2024-07-14"
amount: "1250.8400"
currency: usd
to_base: 1250.84
recurring_id: 994069
payee: Paycheck
original_name: DIRECT DEPOSIT PAYROLL
category_id: 88
notes: null
status: reviewed
is_pending: false
created_at: "2024-07-14T17:00:06.192Z"
updated_at: "2024-07-14T17:00:06.733Z"
is_split_parent: false
split_parent_id: null
is_group_parent: true
group_parent_id: null
manual_account_id: null
plaid_account_id: 119806
tag_ids:
- 94317
source: plaid
external_id: null
has_more: false
limit 2 - paginated response:
summary: Limit 2 paginated response
value:
transactions:
- id: 2112150655
date: "2024-07-28"
amount: "1250.8400"
currency: usd
to_base: 1250.84
recurring_id: 994069
payee: Paycheck
original_name: DIRECT DEPOSIT PAYROLL
category_id: 88
notes: null
status: reviewed
is_pending: false
created_at: "2024-07-28T17:00:06.192Z"
updated_at: "2024-07-28T17:00:06.733Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: 119806
tag_ids:
- 94317
source: plaid
external_id: null
- id: 2112150654
date: "2024-07-24"
amount: "21.9800"
currency: usd
to_base: 21.98
recurring_id: null
payee: Noodle House
original_name: NOODLE HOUSE RESTAURANT #5678
category_id: null
notes: null
status: unreviewed
is_pending: false
created_at: "2024-07-24T17:00:06.192Z"
updated_at: "2024-07-24T17:00:06.192Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: 119805
tag_ids:
- 94317
source: plaid
external_id: null
has_more: true
"400":
description: Invalid request parameters
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Request Validation Failure
errors:
- errMsg: must be integer
instancePath: /query/category_id
schemaPath: "#/properties/query/properties/category_id/type"
keyword: type
params:
type: integer
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
post:
tags:
- transactions (bulk)
summary: Insert one or more transactions.
description: >-
Use this endpoint to add transactions to a budget.
The request body for this endpoint must include a list of transactions with at least one transaction and not more than 500 transactions to insert.
The successful request to this endpoint will return a response
body which will include two arrays:
- `transactions`: A list of transactions that were
successfully inserted.
- `skipped_duplicates`: A list of
transactions that were duplicates of existing transactions and were not
inserted.
operationId: createNewTransactions
requestBody:
required: true
content:
application/json:
schema:
type: object
additionalProperties: false
properties:
transactions:
type: array
minItems: 1
maxItems: 500
description: List of transactions to insert.
items:
$ref: "#/components/schemas/insertTransactionObject"
apply_rules:
type: boolean
default: false
description: If explicitly set to `true`, any rules associated
with the account specified by the `manual_account_id`
property for each transaction will be applied.
skip_duplicates:
type: boolean
default: false
description: If `true`, the system will flag new transactions
that have the same `date`, `payee`, `amount`, and account_id
(plaid or manual), as an existing transaction, as a
duplicate.
Note that deduplication based on
`external_id` will always occur regardless of how this
property is set.
skip_balance_update:
type: boolean
default: false
description: If `true`, and new transactions include a
`manual_account_id`, the balances of these accounts will not
be updated, when the transactions are inserted.
required:
- transactions
examples:
categorized cash transaction:
value:
transactions:
- date: "2024-12-01"
amount: 42.89
payee: Food Town
category_id: 315163
status: reviewed
bare minimum new transaction:
value:
transactions:
- date: "2024-11-01"
amount: 99.99
two new cash transactions:
value:
transactions:
- date: "2024-11-01"
amount: 15.00
payee: Lunch with James
notes: Cash Transaction
category_id: 315163
- date: "2024-11-01"
amount: "-9.99"
payee: me
notes: Interest from Investment Account Cash
status: unreviewed
with external_id and custom_metadata:
value:
transactions:
- date: "2024-12-01"
amount: "19.99"
payee: Test Payee 3
manual_account_id: 219807
external_id: A658214
notes: API Test created Transaction
custom_metadata:
note: API Test Added Custom MetaData
testNumber: 42
testBool: false
testArray:
- 1
- foo
- false
- 42.42
testObject:
foo: bar
duplicate external_id:
value:
transactions:
- date: "2024-12-01"
amount: "19.99"
payee: Test Payee 3
manual_account_id: 219807
external_id: A658214
notes: API Test created Transaction with new external_id
custom_metadata:
note: API Test Added Custom MetaData
testNumber: 42
testBool: false
testArray:
- 1
- foo
- false
- 42.42
testObject:
foo: bar
- date: "2025-06-20"
amount: "250.0000"
payee: Fidelity
manual_account_id: 219807
external_id: "12345"
notes: API Test created Transaction with duplicate external_id
multiple duplicates:
value:
skip_duplicates: true
transactions:
- date: "2025-06-24"
amount: "21.9800"
payee: "Noodle House"
notes: "Duplicate date, payee and amount. Note date may need to be changed in \"Try It\" mode."
plaid_account_id: 119805
- date: "2025-04-20"
amount: "250.0000"
payee: "Fidelity"
category_id: 82
notes: "Duplicate external ID"
external_id: "12345"
manual_account_id: 219807
- date: "2024-12-01"
amount: "19.99"
payee: "Test Payee 3"
notes: "API Test created Transaction"
manual_account_id: 219807
external_id: "A658214"
responses:
"201":
description: Created
content:
application/json:
schema:
$ref: "#/components/schemas/insertTransactionsResponseObject"
examples:
categorized cash transaction:
value:
transactions:
- id: 123456789
date: "2024-12-01"
amount: "42.89"
currency: usd
to_base: 42.89
recurring_id: null
payee: Food Town
category_id: 315163
notes: null
status: reviewed
is_pending: false
created_at: "2024-12-18T04:05:58.072Z"
updated_at: "2024-12-18T04:05:58.072Z"
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: null
tag_ids: []
source: api
external_id: null
custom_metadata: null
plaid_metadata: null
skipped_duplicates: []
bare minimum request:
value:
transactions:
- id: 123456789
date: "2024-11-01"
amount: "99.99"
currency: usd
to_base: 99.99
recurring_id: null
payee: '[No Payee]'
category_id: null
notes: null
status: unreviewed
is_pending: false
created_at: "2024-11-20T16:09:11.544Z"
updated_at: "2024-11-20T16:09:11.544Z"
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: null
tag_ids: []
source: api
external_id: null
custom_metadata: null
plaid_metadata: null
skipped_duplicates: []
two new cash transactions:
value:
transactions:
- id: 123456789
date: "2024-11-01"
amount: "15.00"
currency: usd
to_base: 15
recurring_id: null
payee: Lunch with James
category_id: null
notes: Cash Transaction
status: unreviewed
is_pending: false
created_at: "2024-11-20T16:10:23.395Z"
updated_at: "2024-11-20T16:10:23.395Z"
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: null
tag_ids: []
source: api
external_id: null
custom_metadata: null
plaid_metadata: null
- id: 123456790
date: "2024-11-01"
amount: "-9.99"
currency: usd
to_base: -9.99
recurring_id: null
payee: me
category_id: null
notes: Interest from Investment Account Cash
status: unreviewed
is_pending: false
created_at: "2024-11-20T16:10:23.395Z"
updated_at: "2024-11-20T16:10:23.395Z"
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: null
tag_ids: []
source: api
external_id: null
custom_metadata: null
plaid_metadata: null
skipped_duplicates: []
with external_id and custom_metadata:
value:
transactions:
- id: 123456789
date: "2024-12-01"
amount: "19.99"
currency: usd
to_base: 19.99
recurring_id: null
payee: Test Payee 3
category_id: null
notes: API Test created Transaction
status: unreviewed
is_pending: false
created_at: "2024-11-20T16:15:19.475Z"
updated_at: "2024-11-20T16:15:19.475Z"
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: 219807
plaid_account_id: null
tag_ids: []
source: api
external_id: A658214
custom_metadata:
note: API Test Added Custom MetaData
testNumber: 42
testBool: false
testArray:
- 1
- foo
- false
- 42.42
testObject:
foo: bar
skipped_duplicates: []
duplicate external id skipped:
value:
transactions:
- id: 123456789
date: "2024-12-01"
amount: "19.99"
currency: usd
to_base: 19.99
recurring_id: null
payee: Test Payee 3
category_id: null
notes: API Test created Transaction with new external_id
status: unreviewed
is_pending: false
created_at: "2025-07-18T14:15:23.159Z"
updated_at: "2025-07-18T14:15:23.159Z"
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: 219807
plaid_account_id: null
tag_ids: []
source: api
external_id: A658214
custom_metadata:
note: API Test Added Custom MetaData
testNumber: 42
testBool: false
testArray:
- 1
- foo
- false
- 42.42
testObject:
foo: bar
skipped_duplicates:
- reason: duplicate_external_id
request_transactions_index: 1
existing_transaction_id: 2112150651
request_transaction:
date: "2025-06-20"
amount: "250.0000"
payee: Fidelity
manual_account_id: 219807
external_id: "12345"
notes: API Test created Transaction with duplicate external_id
multiple skipped duplicates:
value:
transactions:
- id: 123456789
date: "2024-12-01"
amount: "19.99"
currency: usd
to_base: 19.99
recurring_id: null
payee: Test Payee 3
category_id: null
notes: API Test created Transaction
status: unreviewed
is_pending: false
created_at: "2025-07-18T14:05:29.253Z"
updated_at: "2025-07-18T14:05:29.253Z"
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: 219807
plaid_account_id: null
tag_ids: []
source: api
external_id: A658214
skipped_duplicates:
- reason: duplicate_payee_amount_date
request_transactions_index: 0
existing_transaction_id: 2112150654
request_transaction:
date: "2025-06-24"
amount: "21.9800"
payee: Noodle House
notes: Duplicate date, payee and amount. Note date may need to be changed in "Try It" mode.
plaid_account_id: 119805
- reason: duplicate_external_id
request_transactions_index: 1
existing_transaction_id: 2112150651
request_transaction:
date: "2025-04-20"
amount: "250.0000"
payee: Fidelity
category_id: 82
notes: Duplicate external ID
external_id: "12345"
manual_account_id: 219807
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
invalid ids in new transactions:
value:
message: Request Validation Failure
errors:
- errMsg: "transactions[0] manual account ID does not exist: 9999999"
transaction_index: 0
error: Invalid Manual Account ID
invalid_property: manual_account_id
manual_account_id: 9999999
- errMsg: "transactions[1] manual account ID does not exist: 9999999"
transaction_index: 1
error: Invalid Manual Account ID
invalid_property: manual_account_id
manual_account_id: 9999999
- errMsg: "transactions[2] recurring ID does not exist: 88888888"
transaction_index: 2
error: Invalid Recurring ID
invalid_property: recurring_id
recurring_id: 88888888
duplicate external_ids within request:
value:
message: Request Validation Failure
errors:
- errMsg: Duplicate External IDs found in the request body
error: Duplicate External ID
transaction_property: external_id
external_id: "12345"
transactions_indices:
- 0
- 1
- errMsg: Duplicate External IDs found in the request body
error: Duplicate External ID
transaction_property: external_id
external_id: "54321"
transactions_indices:
- 2
- 3
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
put:
tags:
- transactions (bulk)
summary: Update multiple transactions
description: >-
Modifies the properties of multiple existing transactions in a single request.
You may submit complete transaction objects from the response returned by a `GET /transactions` in the request body for each transaction, however only certain
properties can be updated using this API. The following system set properties are
accepted in the request body, but their values will be ignored: `id`, `to_base`, `is_pending`, `created_at`, `updated_at`, `source`, and `plaid_metadata`.
Transactions that have been previously split or grouped may not be
modified by this endpoint. Therefore the `is_split_parent`, `split_parent_id`, `is_group_parent`, `group_parent_id`, and `children` properties are also ignored when provided in the request body.
Each transaction in the array **must** include an `id` property to identify which transaction to update, along with at least one other property to be updated. For example, a transaction object that contains only an `id` and `category_id` property is valid.
The request can include between 1 and 500 transactions to update in a single call.
operationId: updateTransactions
requestBody:
required: true
content:
application/json:
schema:
type: object
additionalProperties: false
properties:
transactions:
type: array
minItems: 1
maxItems: 500
description: List of transactions to update. Each transaction
must have an `id` property and at least one other property
to update.
items:
allOf:
- type: object
required: [id]
properties:
id:
type: integer
format: int64
description: The ID of the transaction to update
- $ref: "#/components/schemas/updateTransactionObject"
required:
- transactions
examples:
categorize multiple transactions:
value:
transactions:
- id: 2112150654
category_id: 315162
notes: "Treat restaurants the same as groceries"
- id: 2112150649
category_id: 315162
notes: "Treat restaurants the same as groceries"
- id: 2112140372
category_id: 315162
notes: "Treat restaurants the same as groceries"
update with full objects:
value:
transactions:
- id: 2112150688
date: "2025-07-17"
amount: "4.1300"
currency: "usd"
to_base: 4.13
recurring_id: 994081
payee: "Holey Donuts"
category_id: 315164
notes: "Coffee - cash"
status: "reviewed"
is_pending: false
created_at: "2025-07-17T17:00:06.192Z"
updated_at: "2025-07-17T17:00:06.192Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: null
tag_ids:
- 94317
source: "csv"
external_id: null
- id: 2112150649
category_id: 315162
notes: "Treat restaurants the same as groceries"
update with errors:
value:
transactions:
- id: 9999999
notes: "Invalid transaction ID"
- id: 2112150688
category_id: 999999999
manual_account_id: 999999999
notes: "Invalid category and manual account IDs"
- id: 2112150649
plaid_account_id: 999999999
tag_ids: [888888888, 999999999]
notes: "Invalid tag and plaid account IDs"
- id: 2112150649
additional_tag_ids: [888888888, 999999999]
notes: "Invalid additional_tag_ids"
- id: 2212150657
notes: "Transaction belongs to locked plaid account"
payee: "New Payee"
amount: "100.0000"
currency: "jpy"
responses:
"200":
description: Transactions successfully updated
content:
application/json:
schema:
properties:
transactions:
items:
$ref: "#/components/schemas/transactionObject"
type: array
required:
- transactions
examples:
bulk update transactions:
value:
transactions:
- id: 2112150654
date: "2025-06-24"
amount: "21.9800"
currency: "usd"
to_base: 21.98
recurring_id: null
payee: "Noodle House"
category_id: 315162
notes: "Treat restaurants the same as groceries"
status: "reviewed"
is_pending: false
created_at: "2025-06-24T17:00:06.192Z"
updated_at: "2025-06-24T17:00:06.192Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: 119805
tag_ids:
- 94317
source: "plaid"
external_id: null
custom_metadata: null
- id: 2112150649
date: "2025-06-18"
amount: "4.1300"
currency: "usd"
to_base: 4.13
recurring_id: 994081
payee: "Holey Donuts"
category_id: 315162
notes: "Treat restaurants the same as groceries"
status: "reviewed"
is_pending: false
created_at: "2025-06-18T17:00:06.192Z"
updated_at: "2025-06-18T17:00:06.192Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: null
tag_ids:
- 94317
source: "csv"
external_id: null
custom_metadata: null
- id: 2112140372
date: "2025-06-12"
amount: "50.00"
currency: "usd"
to_base: 50
recurring_id: null
payee: "Starbucks"
category_id: 315162
notes: "Treat restaurants the same as groceries"
status: "reviewed"
is_pending: false
created_at: "2025-06-12T17:00:06.192Z"
updated_at: "2025-06-12T17:00:06.733Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: 119807
tag_ids: []
source: "plaid"
external_id: null
custom_metadata: null
update with full objects:
value:
transactions:
- id: 2112150688
date: "2025-07-17"
amount: "4.1300"
currency: "usd"
to_base: 4.13
recurring_id: 994081
payee: "Holey Donuts"
category_id: 315164
notes: "Coffee - cash"
status: "reviewed"
is_pending: false
created_at: "2025-07-17T17:00:06.192Z"
updated_at: "2025-07-17T17:00:06.192Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: null
tag_ids:
- 94317
source: "csv"
external_id: null
custom_metadata: null
- id: 2112150649
date: "2025-06-18"
amount: "4.1300"
currency: "usd"
to_base: 4.13
recurring_id: 994081
payee: "Holey Donuts"
category_id: 315162
notes: "Treat restaurants the same as groceries"
status: "reviewed"
is_pending: false
created_at: "2025-06-18T17:00:06.192Z"
updated_at: "2025-06-18T17:00:06.192Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: null
tag_ids:
- 94317
source: "csv"
external_id: null
custom_metadata: null
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
invalid ids in id list:
value:
message: Request Validation Failure
errors:
- errMsg: "transactions[0] manual account ID does not exist: 999999999"
transaction_index: 0
error: Invalid Manual Account ID
invalid_property: manual_account_id
manual_account_id: 999999999
- errMsg: "transactions[1] manual account ID does not exist: 999999999"
transaction_index: 1
error: Invalid Manual Account ID
invalid_property: manual_account_id
manual_account_id: 999999999
- errMsg: "transactions[2] recurring ID does not exist: 888888888"
transaction_index: 2
error: Invalid Recurring ID
invalid_property: recurring_id
recurring_id: 888888888
update with errors:
value:
message: Request Validation Failure
errors:
- errMsg: "There is no transaction with the id: 9999999"
error: Invalid Transaction ID
invalid_property: id
transaction_id: 9999999
transaction_index: 0
- errMsg: "transactions[1] category ID does not exist: 999999999"
transaction_index: 1
error: Invalid Category ID
invalid_property: category_id
category_id: 999999999
- errMsg: "transactions[1] manual account ID does not exist: 999999999"
transaction_index: 1
error: Invalid Manual Account ID
invalid_property: manual_account_id
manual_account_id: 999999999
- errMsg: "transactions[2] plaid account ID does not exist: 999999999"
transaction_index: 2
error: Invalid Plaid Account ID
invalid_property: plaid_account_id
plaid_account_id: 999999999
- errMsg: "transactions[2] tag_ids[0] ID does not exist: 888888888"
transaction_index: 2
error: Invalid Tag ID
invalid_property: tag_ids
tag_id: 888888888
tag_ids_index: 0
- errMsg: "transactions[2] tag_ids[1] ID does not exist: 999999999"
transaction_index: 2
error: Invalid Tag ID
invalid_property: tag_ids
tag_id: 999999999
tag_ids_index: 1
- errMsg: "transactions[3] additional_tag_ids[0] ID does not exist: 888888888"
transaction_index: 3
error: Invalid Tag ID
invalid_property: additional_tag_ids
tag_id: 888888888
additional_tag_ids_index: 0
- errMsg: "transactions[3] additional_tag_ids[1] ID does not exist: 999999999"
transaction_index: 3
error: Invalid Tag ID
invalid_property: additional_tag_ids
tag_id: 999999999
additional_tag_ids_index: 1
- errMsg: "Cannot change the currency for a transaction that belongs to a Plaid Account which is not configured to allow modifications to transactions. Plaid Account ID: 119804"
error: Transaction belongs to a locked Plaid account
id: 2212150657
transaction_index: 4
locked_property: currency
- errMsg: "Cannot change the amount for a transaction that belongs to a Plaid Account which is not configured to allow modifications to transactions. Plaid Account ID: 119804"
error: Transaction belongs to a locked Plaid account
id: 2212150657
transaction_index: 4
locked_property: amount
duplicate external_ids within request:
value:
message: Request Validation Failure
errors:
- errMsg: Duplicate External IDs found in the request body
error: Duplicate External ID
transaction_property: external_id
external_id: "12345"
transactions_indices:
- 0
- 1
- errMsg: Duplicate External IDs found in the request body
error: Duplicate External ID
transaction_property: external_id
external_id: "54321"
transactions_indices:
- 2
- 3
invalid ids:
value:
message: Request Validation Failure
errors:
- errMsg: "There is no transaction with the id: 1"
error: Invalid Transaction ID
invalid_property: id
transaction_id: 1
transaction_index: 0
- errMsg: "There is no transaction with the id: 2"
error: Invalid Transaction ID
invalid_property: id
transaction_id: 2
transaction_index: 1
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
delete:
tags:
- transactions (bulk)
summary: Bulk delete existing transactions
description: >-
Deletes the transaction with the IDs specified in the request body.
If any of the specified transactions are a split transaction or a split parent, or if any are a grouped transactions or part of a transaction group, the request will fail with a suggestion on how to unsplit or ungroup the transaction(s) prior to deletion. This will also fail if any of the specified transaction IDs do not exist.
Otherwise, the specified transactions are deleted.
Use with caution. This action is not reversible!
operationId: deleteTransactions
requestBody:
required: true
content:
application/json:
schema:
type: object
additionalProperties: false
properties:
ids:
type: array
description: Array of existing Transaction IDs to delete
minItems: 1
maxItems: 500
items:
type: integer
format: int64
required:
- ids
examples:
delete three transactions:
value:
ids:
- 2112150653
- 2112150654
- 2112150655
duplicate ids:
value:
ids:
- 2112150653
- 2112150653
- 2112150654
- 2112150654
invalid ids:
value:
ids:
- 2112150653
- 9999999999
- 2112150654
responses:
"204":
description: No Content
"400":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Invalid Request Body
errors:
- errMsg: "Duplicate transaction ID found: 2112150653"
transaction_id: 2112150653
ids_index: 0
invalid_property: ids
- errMsg: "Duplicate transaction ID found: 2112150653"
transaction_id: 2112150653
ids_index: 1
invalid_property: ids
- errMsg: "Duplicate transaction ID found: 2112150654"
transaction_id: 2112150654
ids_index: 2
invalid_property: ids
- errMsg: "Duplicate transaction ID found: 2112150654"
transaction_id: 2112150654
ids_index: 3
invalid_property: ids
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Request Validation Failure
errors:
- errMsg: "There is no transaction with the id: 8888888888"
ids_index: 0
id: 8888888888
- errMsg: "There is no transaction with the id: 9999999999"
ids_index: 1
id: 9999999999
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/transactions/{id}:
get:
tags:
- transactions
summary: Get a single transaction
description: >
Retrieves the details of a specific transaction by its ID, including the
following properties which are not returned by default in the response
to a `GET /transactions` request:
- `plaid_metadata` will either be `null` or contain the metadata for
transactions associated with an account that is synced via plaid.
- `custom_metadata` will either be `null` or contain any custom_metadata
added to transactions that were inserted or updated via the API.
- `files` will be a list of objects that describe any attachments to the
transaction.
If `is_group_parent` is true in the returned transaction, the object will also
include the `children` property which will contain a list of the
original transactions that make up the transaction group.
If `is_split_parent` is true in the returned transaction, the object will also
include the `children` property which will contain a list
of the split transactions.
operationId: getTransactionById
parameters:
- name: id
in: path
description: ID of the transaction to retrieve
required: true
schema:
type: integer
format: int64
examples:
basic transaction:
summary: Basic transaction by id request
value: 2112150654
transaction with plaid metadata:
summary: Transaction with plaid metadata
value: 2112150655
transaction group:
summary: Transaction group
value: 2112140959
id not found:
summary: Example of an id that doesn't exist
value: 9999999999999
responses:
"200":
description: Transaction Object with the requested transaction.
content:
application/json:
schema:
$ref: "#/components/schemas/transactionObject"
examples:
basic transaction:
value:
id: 2112150654
date: "2024-07-24"
amount: "21.9800"
currency: usd
to_base: 21.98
recurring_id: null
payee: Noodle House
original_name: NOODLE HOUSE RESTAURANT #5678
category_id: null
notes: null
status: unreviewed
is_pending: false
created_at: "2024-07-24T17:00:06.192Z"
updated_at: "2024-07-24T17:00:06.192Z"
split_parent_id: null
children: []
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: 119805
tag_ids: []
source: csv
external_id: null
transaction with plaid metadata:
value:
id: 2112150655
date: "2025-05-28"
amount: "1250.8400"
currency: usd
to_base: 1250.84
recurring_id: 994069
payee: Paycheck
original_name: DIRECT DEPOSIT PAYROLL
category_id: null
notes: null
status: pending
is_pending: true
created_at: "2025-05-28T17:00:06.192Z"
updated_at: "2025-05-28T17:00:06.733Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: 119806
tag_ids:
- 94317
source: plaid
external_id: null
custom_metadata: null
plaid_metadata:
note: This is an artificially constructed example of metadata
account_id: 9DYYMLBoaxIqRkAOKaVDuaPZrmE5qJhVxyZyv
account_owner: null
amount: "1250.8400"
authorized_datetime: "2025-05-28T17:00:06.192Z"
counterparties:
- confidence_level: LOW
entity_id: null
logo_url: null
name: Employers Inc.
transaction group:
value:
id: 2112140959
date: "2025-05-17"
amount: "25.6900"
currency: usd
to_base: 25.69
recurring_id: null
payee: Valero
original_name: Valero
category_id: 315174
notes: Net Gas for roadtrip
status: reviewed
is_pending: false
created_at: "2025-05-17T17:00:06.192Z"
updated_at: "2025-05-17T17:00:06.733Z"
split_parent_id: null
is_group_parent: true
group_parent_id: null
manual_account_id: null
plaid_account_id: null
tag_ids:
- 94318
- 94317
source: csv
external_id: null
children:
- id: 2112150647
date: "2025-05-17"
amount: "25.000"
currency: usd
to_base: 25
recurring_id: null
payee: Me
original_name: Me
category_id: 315174
notes: Gas repay from Tim for roadtrip
status: reviewed
is_pending: false
created_at: "2025-05-17T17:00:06.192Z"
updated_at: "2025-05-17T17:00:06.733Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: 2112140959
manual_account_id: null
plaid_account_id: null
tag_ids:
- 94318
- 94317
source: csv
external_id: null
- id: 2112150859
date: "2025-05-16"
amount: "25.000"
currency: usd
to_base: 25
recurring_id: null
payee: Me
category_id: 315174
notes: Gas repay from Liz for roadtrip
status: reviewed
is_pending: false
created_at: "2025-05-16T17:00:06.192Z"
updated_at: "2025-05-16T17:00:06.192Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: 2112140959
manual_account_id: null
plaid_account_id: null
tag_ids:
- 94318
- 94317
source: csv
external_id: null
- id: 2112150659
date: "2025-05-15"
amount: "75.6900"
currency: usd
to_base: 75.69
recurring_id: null
payee: Valero
category_id: 315174
notes: Gas on roadtrip with Tim and Liz
status: reviewed
is_pending: false
created_at: "2025-05-15T17:00:06.192Z"
updated_at: "2025-05-15T17:00:06.733Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: 2112140959
manual_account_id: null
plaid_account_id: 119805
tag_ids:
- 94318
- 94317
source: plaid
external_id: null
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Request Validation Failure
errors:
- errMsg: must be integer
instancePath: /path/id
schemaPath: "#/properties/path/properties/id/type"
keyword: type
params:
type: integer
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no transaction with the id: 543210."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
put:
tags:
- transactions
summary: Update an existing transaction
description: >-
Modifies the properties of an existing transaction.
You may submit the response from a `GET /transactions/{id}` as the request body, however only certain
properties can be updated using this API. The following system set properties are
accepted in the request body but their values will be ignored: `id`, `to_base`, `is_pending`, `created_at`, `updated_at`, `source`, and `plaid_metadata`.
Transactions that have been previously split or grouped may not be
modified by this endpoint. Therefore the `is_split_parent`, `split_parent_id`, `is_group_parent`, `group_parent_id`, and `children` properties are also ignored when provided in the request body.
It is also possible to provide only the properties to be updated in the
request body, as long as the request includes at least one of the
properties that is not listed above. For example a request body that contains only
an `category_id` attribute is valid.
operationId: updateTransaction
parameters:
- name: id
in: path
description: ID of the transaction to update
required: true
schema:
type: integer
format: int64
examples:
basic transaction:
summary: Basic transaction by id request
value: 2112140361
id not found:
summary: Example of an id that doesn't exist
value: 9999999999999
- name: update_balance
in: query
description: Set this to `false` to skip updating the transaction's
associated account balance. Default behavior is to update balances.
required: false
schema:
type: boolean
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/updateTransactionObject"
examples:
update categories simple:
value:
category_id: 315162
update transaction category with previous get response:
value:
id: 2112140361
date: "2024-12-09"
amount: "300.00"
currency: usd
to_base: 300
recurring_id: null
payee: Best Buy
category_id: 315162
notes: Electronics
status: reviewed
is_pending: false
created_at: "2024-12-09T17:00:06.192Z"
updated_at: "2024-12-09T17:00:06.733Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: 119810
tag_ids: []
source: plaid
external_id: null
responses:
"201":
description: Transaction successfully updated
content:
application/json:
schema:
$ref: "#/components/schemas/transactionObject"
examples:
transaction with updated category:
value:
id: 2112140361
date: "2024-12-09"
amount: "300.00"
currency: usd
to_base: 300
recurring_id: null
payee: Best Buy
category_id: 315162
notes: Electronics
status: reviewed
is_pending: false
created_at: "2024-12-09T17:00:06.192Z"
updated_at: "2024-12-09T17:00:06.733Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: 119810
tag_ids: []
source: plaid
external_id: null
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Request Validation Failure
errors:
- errMsg: must be integer
instancePath: /path/id
schemaPath: "#/properties/path/properties/id/type"
keyword: type
params:
type: integer
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no transaction with the id: 543210."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
delete:
tags:
- transactions
summary: Delete a transaction
description: >-
Deletes the transaction with the ID specified on the path.
If the specified transaction is a split transaction or a split parent, or if it is a grouped transactions or part of a transaction group, the request will fail with a suggestion on how to unsplit or ungroup the transaction(s) prior to deletion. Otherwise, the specified transaction is deleted.
Use with caution. This action is not reversible!
operationId: deleteTransactionById
parameters:
- in: path
name: id
description: ID of the transaction to delete
required: true
schema:
type: integer
format: int64
examples:
delete transaction:
summary: Simple transaction delete
value: 2112140361
delete split transaction:
value: 2112140459
delete transaction group:
value: 2112140959
id not found:
summary: Example of an id that doesn't exist
value: 543210
responses:
"204":
description: No Content
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no transaction with the id: 543210."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/transactions/group:
post:
tags:
- transactions (group)
summary: Create a transaction group
description: >
Specify a set of existing transaction IDs to group together as a single
grouped transaction.
The new transaction will have an amount equal to the sum of the grouped
transaction amounts. If the
grouped transactions have different currencies, the new group
transaction will be set in the user's
default currency.
After a transaction has been grouped, the original transactions are no
longer shown on the
transactions page or returned by a `GET /transactions` request. The
newly created grouped
transaction is returned instead.
To see the details of the original transactions that were used to create
a transaction group, use the
`GET /transactions/{id}` endpoint and pass the ID of the grouped
transaction. The grouped transactions will
be included in the `children` property of the transaction returned in
the response
operationId: groupTransactions
requestBody:
required: true
content:
application/json:
schema:
type: object
additionalProperties: false
properties:
ids:
type: array
minItems: 2
maxItems: 500
description: List of existing transaction IDs to group. Split
and recurring transactions may not be grouped. Transactions
that are already grouped must be ungrouped before being
regrouped.
items:
type: integer
format: int64
date:
type: string
format: date
description: Date for the new grouped transaction in ISO 8601
format.
payee:
type: string
description: |
The payee for the new grouped transaction.
minLength: 0
category_id:
type: integer
format: int64
nullable: true
description: The ID of an existing category to assign to the
grouped transaction. If not set and all the grouped
transactions have the same category, the grouped transaction
will inherit the category, otherwise the new transaction
will have no category.
notes:
type: string
nullable: true
description: |
Notes for the grouped transaction.
status:
type: string
description: If set, must be either `reviewed` or
`unreviewed`. If not set, defaults to `reviewed`.
enum:
- reviewed
- unreviewed
tag_ids:
type: array
description: A list of IDs for the tags associated with the
grouped transaction. Each ID must match an existing tag
associated with the user's account. If not set, no tags will
be associated with the created transaction.
items:
type: integer
format: int64
required:
- ids
- date
- payee
examples:
group inherits category:
value:
ids:
- 2112140365
- 2112140361
payee: Home Entertainment Transactions
date: "2024-12-10"
responses:
"201":
description: The new grouped parent transaction with populated
children attribute
content:
application/json:
schema:
$ref: "#/components/schemas/transactionObject"
examples:
group inherits category:
value:
id: 123456789
date: "2024-12-10"
amount: "375.0000"
currency: usd
to_base: 375
recurring_id: null
payee: Home Entertainment Transactions
category_id: 315628
notes: null
status: reviewed
is_pending: false
created_at: "2024-12-18T14:45:03.366Z"
updated_at: "2024-12-18T14:45:03.366Z"
split_parent_id: null
is_group_parent: true
group_parent_id: null
manual_account_id: null
plaid_account_id: null
tag_ids: []
source: api
external_id: null
custom_metadata: null
children:
- id: 2112140365
date: "2024-11-10"
amount: "75.00"
currency: usd
to_base: 75
recurring_id: null
payee: Target
category_id: 315628
notes: Household items
status: reviewed
is_pending: false
created_at: "2024-11-10T17:00:06.192Z"
updated_at: "2024-11-10T17:00:06.733Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: 123456789
manual_account_id: null
plaid_account_id: 119809
tag_ids: []
source: plaid
external_id: null
- id: 2112140361
date: "2024-11-09"
amount: "300.00"
currency: usd
to_base: 300
recurring_id: null
payee: Best Buy
category_id: 315628
notes: Electronics
status: reviewed
is_pending: false
created_at: "2024-11-09T17:00:06.192Z"
updated_at: "2024-11-09T17:00:06.733Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: 123456789
manual_account_id: null
plaid_account_id: 119810
tag_ids: []
source: plaid
external_id: null
group with all reviewed children:
summary: When all children have status 'reviewed', the grouped transaction also has status 'reviewed'
value:
id: 123456789
date: "2024-12-25"
amount: "0.0000"
currency: usd
to_base: 0
recurring_id: null
payee: Grouped Transaction Payee
category_id: 82
notes: API Created Test Transaction Group
status: reviewed
is_pending: false
created_at: "2025-11-13T21:39:27.609Z"
updated_at: "2025-11-13T21:39:27.609Z"
split_parent_id: null
is_group_parent: true
group_parent_id: null
manual_account_id: null
plaid_account_id: null
tag_ids: [94318]
source: api
external_id: null
custom_metadata: null
children:
- id: 2112150653
date: "2025-10-22"
amount: "-847.2200"
currency: usd
to_base: -847.22
recurring_id: null
payee: Credit Card Payment
category_id: 82
notes: null
status: reviewed
is_pending: false
created_at: "2025-10-22T17:00:06.192Z"
updated_at: "2025-10-22T17:00:06.733Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: 123456789
manual_account_id: null
plaid_account_id: 119804
tag_ids: []
source: plaid
external_id: null
custom_metadata: null
- id: 2112150652
date: "2025-10-21"
amount: "847.2200"
currency: usd
to_base: 847.22
recurring_id: null
payee: Transfer to Credit Card
category_id: 82
notes: "Lenny's Amex Bill"
status: reviewed
is_pending: false
created_at: "2025-10-21T17:00:06.192Z"
updated_at: "2025-10-21T17:00:06.733Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: 123456789
manual_account_id: null
plaid_account_id: 119806
tag_ids: []
source: plaid
external_id: null
custom_metadata: null
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
missing ids:
value:
message: Request Validation Failure
errors:
- errMsg: "There is no transaction with the id: 89999999"
ids_index: 0
id: 89999999
- errMsg: "There is no transaction with the id: 99999999"
ids_index: 1
id: 99999999
duplicate ids:
value:
message: Request Validation Failure
errors:
- errMsg: "Duplicate transaction ID found: 2112150653"
ids_index: 1
transaction_id: 2112150653
invalid_property: ids
split transactions:
value:
message: Request Validation Failure
errors:
- errMsg: "Transaction with id 2112150653 is a split transaction and cannot be added to a transaction group."
ids_index: 0
id: 2112150653
- errMsg: "Transaction with id 2112150654 is a split transaction and cannot be added to a transaction group."
ids_index: 1
id: 2112150654
grouped transactions:
value:
message: Request Validation Failure
errors:
- errMsg: "Transaction with id 2112140959 is a transaction group and cannot be added to another transaction group."
ids_index: 0
id: 2112140959
- errMsg: "Transaction with id 2112150647 is in a transaction group already and cannot be added to another transaction group."
ids_index: 1
id: 2112150647
group_parent_id: 2112140959
recurring transactions:
value:
message: Request Validation Failure
errors:
- errMsg: "Transaction 2112150655 is a recurring transaction and cannot be added to a transaction group."
ids_index: 0
id: 2112150655
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/transactions/group/{id}:
delete:
tags:
- transactions (group)
summary: Delete a transaction group
description: >-
Deletes the transaction group with the ID specified on the path.
The transactions within the group are not removed and will subsequently
be treated as "normal" ungrouped transactions.
operationId: ungroupTransactions
parameters:
- in: path
name: id
description: ID of the transaction group to delete
required: true
schema:
type: integer
format: int64
examples:
delete transaction group:
summary: Simple transaction group delete
value: 2112140959
delete non group transaction:
summary: ID is not a transaction group
value: 2112150649
id not found:
summary: Example of an id that doesn't exist
value: 543210
responses:
"204":
description: No Content
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no transaction with the id: 543210"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/transactions/split/{id}:
post:
tags:
- transactions (split)
summary: Split a transaction
description: >-
Splits an existing transaction into a set of smaller child
transactions.
After a transaction has been split, the original
transaction is no longer shown on the transactions page or returned by a
`GET /transactions` request. The newly created child transactions are
returned instead.
To see the details of the original parent transaction after it has been
split, use the `GET /transactions/{id}` endpoint and pass the value of
the `split_parent_id` of one of the children.
operationId: splitTransaction
parameters:
- name: id
in: path
description: ID of the transaction to spit
required: true
schema:
type: integer
format: int64
examples:
spit transaction:
summary: Basic transaction by id request
value: 2112150650
already split transaction:
summary: Attempt to split a transaction that has already been split
value: 2112140459
id not found:
summary: Example of an id that doesn't exist
value: 9999999999999
requestBody:
required: true
content:
application/json:
schema:
type: object
additionalProperties: false
properties:
child_transactions:
type: array
minItems: 2
maxItems: 500
description: List of child transactions to create. The sum of
the `amounts` must match the split transaction amount.
items:
$ref: "#/components/schemas/splitTransactionObject"
required:
- child_transactions
examples:
split 88.45 Transaction:
value:
child_transactions:
- amount: 44.23
payee: Food Town - Lenny
- amount: 44.22
payee: Food Town - Penny
invalid math on 88.45 Transaction:
value:
child_transactions:
- amount: 1.5
payee: Food Town - Lenny
- amount: 1.5
payee: Food Town - Penny
responses:
"201":
description: The new split parent transaction with populated children
attribute
content:
application/json:
schema:
$ref: "#/components/schemas/transactionObject"
examples:
split 88.45 Transaction:
value:
id: 2112150650
date: "2024-10-19"
amount: "88.4500"
currency: usd
to_base: 88.45
recurring_id: null
payee: Food Town
category_id: 315162
notes: null
status: reviewed
is_pending: false
created_at: "2024-10-19T17:00:06.192Z"
updated_at: "2024-11-30T22:25:53.232Z"
split_parent_id: null
is_split_parent: true
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: 119805
tag_ids: []
source: plaid
external_id: null
children:
- id: 2112150750
date: "2024-10-19"
amount: "44.2300"
currency: usd
to_base: 44.23
recurring_id: null
payee: Food Town - Lenny
category_id: 315162
notes: null
status: reviewed
is_pending: false
created_at: "2024-11-30T22:25:53.232Z"
updated_at: "2024-11-30T22:25:53.232Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: 119805
tag_ids: []
source: plaid
external_id: null
- id: 2112150751
date: "2024-10-19"
amount: "44.2200"
currency: usd
to_base: 44.22
recurring_id: null
payee: Food Town - Penny
category_id: 315162
notes: null
status: reviewed
is_pending: false
created_at: "2024-11-30T22:25:53.232Z"
updated_at: "2024-11-30T22:25:53.232Z"
is_split_parent: false
split_parent_id: null
is_group_parent: false
group_parent_id: null
manual_account_id: null
plaid_account_id: 119805
tag_ids: []
source: plaid
external_id: null
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
bad math:
value:
message: Request Validation Failure
errors:
- errMsg: Sum of split transactions do not add up to the original transaction amount.
split recurring:
value:
message: Request Validation Failure
errors:
- errMsg: You cannot split a recurring transaction.
id: 2112150655
split group:
value:
message: Request Validation Failure
errors:
- errMsg: You cannot split a group transaction. Ungroup it before splitting.
split split:
value:
message: Request Validation Failure
errors:
- errMsg: You cannot split an already split transaction. Unsplit it before splitting again.
missing amount in child transaction:
value:
message: Invalid Request Body
errors:
- errMsg: "child_transactions[0] is missing required property 'amount' in request body."
child_transactions_index: 0
error: Missing required property
invalid_property: amount
invalid category in child transaction:
value:
message: Request Validation Failure
errors:
- errMsg: "child_transactions[0] category ID does not exist: 899999999"
child_transactions_index: 0
error: Invalid category ID
invalid_property: category_id
category_id: 899999999
category group in child transaction:
value:
message: Request Validation Failure
errors:
- errMsg: "child_transactions[0] category ID is a category group and cannot be assigned to a transaction: 86"
child_transactions_index: 0
error: Invalid category ID
invalid_property: category_id
category_id: 86
category_group_name: Food
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
delete:
tags:
- transactions (split)
summary: Unsplit a previously split transactions
description: >-
Deletes the split children of a previously split transactions and
restores the parent transactions to the normal unsplit state.
Use the value of the `split_parent_id`property of a split transaction to
specify the parent ID.
operationId: unsplitTransaction
parameters:
- in: path
name: id
description: ID of the previously split transaction to delete.
required: true
schema:
type: integer
format: int64
examples:
unsplit a transaction:
value: 2112140459
invalid parent id:
value: 2112140361
id not found:
value: 543210
responses:
"204":
description: No Content
"400":
description: Invalid request parameters
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no transaction with the id: 2112140458"
id: 2112140458
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/transactions/{transaction_id}/attachments:
post:
tags:
- transactions (files)
summary: Attach a file to a transaction
operationId: attachFileToTransaction
description: >-
Attaches a file to a transaction. The file must be less than 10MB in size.
The file will be attached to the transaction and can be downloaded from the link returned by a `GET /transactions/attachments/{file_id}` request.
parameters:
- name: transaction_id
in: path
required: true
schema:
type: integer
format: int64
description: The ID of the transaction to attach the file to
examples:
attach file to transaction:
summary: Basic transaction by id request
value: 2112150655
id not found:
summary: Example of an id that doesn't exist
value: 9999999999999
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
required:
- file
properties:
file:
type: string
format: binary
description: |
The file to attach via multipart form encoding. File size may not exceed 10MB.
notes:
type: string
description: Optional notes about the file
example:
file: ./test-attachment.png
notes: "Test file attachment"
responses:
"201":
description: File attached successfully
content:
application/json:
schema:
$ref: "#/components/schemas/transactionAttachmentObject"
example:
id: 1234567890
uploaded_by: 1
name: "receipt.png"
type: "image/png"
size: 4330
notes: null
source: "api"
created_at: "2025-06-11T22:33:20.294Z"
"400":
description: Invalid request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
examples:
invalidFileType:
value:
message: "Invalid Request Body"
errors:
- errMsg: "File type application/zip not allowed. Allowed types are: image/jpeg, image/png, application/pdf, image/heic, image/heif"
fileTooLarge:
value:
message: "Invalid Request Body"
errors:
- errMsg: "File size exceeds maximum allowed size of 10MB"
invalidFileTypeString:
value:
message: "Invalid Request Body"
errors:
- errMsg: "Invalid value for property 'file'. Expected 'object', received 'string'"
error: Invalid type
invalid_property: file
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Transaction not found
/transactions/attachments/{file_id}:
get:
summary: Get a url to download a file attachment
description: Returns a signed url that can be used to download the file
attachment.
operationId: getTransactionAttachmentUrl
tags:
- transactions (files)
parameters:
- name: file_id
in: path
required: true
schema:
type: integer
format: int32
description: The ID of the file attachment to download
examples:
existing file attachment id:
summary: Basic file attachment by id request
value: 1234567890
id not found:
summary: Example of an id that doesn't exist
value: 9999999999999
responses:
"200":
description: Successfully retrieved the file attachment
content:
application/json:
schema:
properties:
url:
type: string
description: The signed url to download the file attachment
expires_at:
type: string
format: date-time
description: The date and time the signed url will expire
required:
- url
- expires_at
example:
url: "https://files.lunchmoney.app/66938-41ebb56a066bf09898de.png?X-Header1=X-Value1&X-Header2=Test-Do-Not-Use"
expires_at: "2025-07-14T12:00:00Z"
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: File attachment not found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: File attachment 1234567890 not found
delete:
summary: Delete a file attachment
operationId: deleteTransactionAttachment
description: >-
Deletes a file attachment from a transaction.
tags:
- transactions (files)
parameters:
- name: file_id
in: path
required: true
schema:
type: integer
format: int32
description: The ID of the file attachment to delete
examples:
existing file attachment id:
summary: Basic file attachment by id request
value: 1234567890
id not found:
summary: Example of an id that doesn't exist
value: 9999999999999
responses:
"204":
description: File attachment successfully deleted
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: File attachment not found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: File attachment 1234567890 not found
/tags:
get:
tags:
- tags
summary: Get All Tags
description: Retrieve a list of all tags associated with the user's
account.
operationId: getAllTags
responses:
"200":
description: A list of tags
content:
application/json:
schema:
type: object
properties:
tags:
type: array
items:
$ref: "#/components/schemas/tagObject"
example:
tags:
- id: 94317
name: Penny's
description: For transactions not related to Lenny
updated_at: "2025-02-28T09:49:03.238Z"
created_at: "2025-01-28T09:49:03.238Z"
text_color: "333"
background_color: "FFE7D4"
archived: false
archived_at: null
- id: 94318
name: Road Trip
description: ""
updated_at: "2025-02-28T09:50:03.238Z"
created_at: "2025-01-28T09:50:03.238Z"
text_color: "333"
background_color: "CFF4F3"
archived: false
archived_at: null
- id: 94319
name: Date Night
description: ""
updated_at: "2025-02-28T09:59:03.238Z"
created_at: "2025-01-28T10:02:03.238Z"
text_color: "333"
background_color: "D7F5CC"
archived: false
archived_at: null
"400":
description: Invalid request parameters
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Request Validation Failure
errors:
- errMsg: must be equal to one of the allowed values
instancePath: /query/format
schemaPath: "#/properties/query/properties/format/enum"
keyword: enum
params:
allowedValues:
- flattened
- nested
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
post:
tags:
- tags
summary: Create a new tag
description: Creates a new tag with the given name
operationId: createTag
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/createTagRequestObject"
examples:
name only:
value:
name: API Created Tag with no description
with description:
value:
name: API Created Tag
description: Description of tag created via API
responses:
"201":
description: Tag Object with the successfully created tag
content:
application/json:
schema:
$ref: "#/components/schemas/tagObject"
examples:
name only:
value:
id: 94350
name: API Created Tag with no description
description: null
created_at: "2024-07-28T01:01:38.716Z"
updated_at: "2024-07-28T01:01:38.716Z"
text_color: null
background_color: null
archived: false
archived_at: null
with description:
value:
id: 94351
name: API Created Tag
description: Description of tag created via API
text_color: null
background_color: null
created_at: "2024-07-28T01:01:38.716Z"
updated_at: "2024-07-28T01:01:38.716Z"
archived: false
archived_at: null
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Invalid Request Body
errors:
- errMsg: Tag with name 'New Tag' already exists
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/tags/{id}:
get:
tags:
- tags
summary: Get a single tag
description: Retrieve the details of a specific tag with the specified ID.
operationId: getTagById
parameters:
- name: id
in: path
description: ID of the tag to retrieve
required: true
schema:
type: integer
format: int32
examples:
tag:
summary: Example of a tags's id
value: 94319
not found:
summary: Example of a tag id that does not exist
value: 543210
responses:
"200":
description: Tag Object with the requested Tag ID
content:
application/json:
schema:
$ref: "#/components/schemas/tagObject"
example:
id: 94319
name: Date Night
description: ""
updated_at: "2025-02-28T09:59:03.238Z"
created_at: "2025-01-28T10:02:03.238Z"
text_color: null
background_color: null
archived: false
archived_at: null
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Request Validation Failure
errors:
- errMsg: must be a valid integer
instancePath: /query/ids/0
schemaPath: "#/properties/query/properties/ids/items/type"
keyword: type
params:
type: integer
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: There is no tag with the id:'543210'
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
put:
tags:
- tags
summary: Update an existing tag
description: >-
Updates an existing tag.
You may submit the response from a `GET /tags/{id}` as the request body; however, only certain
properties can be updated using this API. The following system set properties are
accepted in the request body but their values will be ignored: `id`, `updated_at`, and `created_at`.
It is also possible to provide only the properties to be updated in the
request body, as long as the request includes at least one of the
properties that is not listed above. For example, a request body that contains only a
`name` attribute is valid.
operationId: updateTag
parameters:
- name: id
in: path
description: ID of the tag to update
required: true
schema:
type: integer
format: int32
examples:
tag:
summary: Example of a tags's id
value: 94319
not found:
summary: Example of a tag id that does not exist
value: 543210
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/updateTagRequestObject"
examples:
Update tag name:
value:
name: Updated Tag Name
Update with full object:
value:
id: 94319
name: Updated Tag Name
description: API Updated Description
text_color: "333"
background_color: "FFE7D4"
updated_at: "2025-02-28T09:59:03.238Z"
created_at: "2025-01-28T10:02:03.238Z"
archived: false
archived_at: null
responses:
"200":
description: Tag updated successfully
content:
application/json:
schema:
$ref: "#/components/schemas/tagObject"
examples:
new name:
value:
id: 94319
name: Updated Tag Name
description: null
text_color: null
background_color: null
updated_at: "2025-02-28T09:59:03.238Z"
created_at: "2025-01-28T10:02:03.238Z"
archived: false
archived_at: null
new name and description:
value:
id: 94319
name: Updated Tag Name
description: API Updated Description
text_color: "333"
background_color: "FFE7D4"
updated_at: "2025-02-28T09:59:03.238Z"
created_at: "2025-01-28T10:02:03.238Z"
archived: false
archived_at: null
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Request Validation Failure
errors:
- errMsg: "A request to update a tag must include at least one of the following properties: name, description, archived."
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no tag with the id: 543210."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
delete:
tags:
- tags
summary: Delete a tag
description: >-
Deletes the tag with the ID specified on the path.
If transactions or rules exist with the tag, a dependents object is
returned and the tag is not deleted. This behavior can be overridden by
setting the `force` parameter to `true`.
operationId: deleteTag
parameters:
- in: path
name: id
description: ID of the tag to delete
required: true
schema:
type: integer
format: int32
examples:
delete tag:
summary: Simple tag delete
value: 94319
delete tag with dependents:
summary: Tag request with dependents
value: 94317
id not found:
summary: Example of an id that doesn't exist
value: 543210
- in: query
name: force
description: Set to true to force deletion even if there are
dependencies
required: false
schema:
type: boolean
default: false
responses:
"204":
description: No Content
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no tag with the id: 543210."
"422":
description: Unprocessable Content
content:
application/json:
schema:
$ref: "#/components/schemas/deleteTagResponseWithDependencies"
example:
tag_name: Tag to be Deleted
dependents:
rules: 1
transactions: 10
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/recurring_items:
get:
tags:
- recurring_items
summary: Get all recurring items
description: Retrieve recurring items for a specified time frame.
operationId: getAllRecurring
parameters:
- name: start_date
in: query
schema:
type: string
format: date
description: Indicates the beginning of the range used to populate the
`matching` object in the recurring items. If omitted, the current
month will be used as the range.
Required if end_date exists.
- name: end_date
in: query
schema:
type: string
format: date
description: "Indicates the end of the range used to populate the
`matching` object in the recurring items. Required if start_date
exists. "
- name: include_suggested
in: query
schema:
type: boolean
description: When set to true will include recurring items that have
been suggested by the system, but have not been reviewed and are
not actively updating transactions.
responses:
"200":
description: A list of recurring items
content:
application/json:
schema:
type: object
properties:
recurring_items:
type: array
items:
$ref: "#/components/schemas/recurringObject"
example:
recurring_items:
recurring_items:
- id: 994069
description: Income
status: reviewed
transaction_criteria:
start_date: "2024-09-01"
end_date: "2024-10-31"
anchor_date: "2024-09-14"
granularity: month
quantity: 1
payee: Penny Lane
amount: "1250.8400"
to_base: 1250.84
currency: usd
plaid_account_id: 119806
manual_account_id: null
overrides:
payee: Paycheck
category_id: 88
matches:
request_start_date: "2024-10-01"
request_end_date: "2024-10-31"
expected_occurrence_dates:
- "2024-10-14"
- "2024-10-28"
found_transactions:
- date: "2024-10-14"
transaction_id: 2212150658
missing_transaction_dates:
- "2024-10-28"
created_by: 18328
created_at: "2024-07-28T01:01:38.716Z"
updated_at: "2024-07-28T01:01:38.716Z"
source: manual
- id: 994079
description: Monthly rent payable to Mrs Smith
status: reviewed
transaction_criteria:
start_date: "2024-09-01"
end_date: "2024-10-31"
anchor_date: "2024-09-01"
granularity: month
quantity: 1
payee: '[No Payee]'
amount: "850.0000"
to_base: 850
currency: usd
plaid_account_id: 119806
manual_account_id: null
overrides:
payee: Rent
notes: Monthly rent payable to Mrs Smith
category_id: 83
matches:
request_start_date: "2024-10-01"
request_end_date: "2024-10-31"
expected_occurrence_dates:
- "2024-10-01"
found_transactions:
- date: "2024-10-01"
transaction_id: 2212150656
missing_transaction_dates: []
created_by: 18328
created_at: "2025-06-28T01:01:38.195Z"
updated_at: "2025-06-28T01:01:38.195Z"
source: manual
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Request Validation Failure
errors:
- errMsg: must be a valid integer
instancePath: /query/ids/0
schemaPath: "#/properties/query/properties/ids/items/type"
keyword: type
params:
type: integer
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no recurring item with the id: 543210."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/recurring_items/{id}:
get:
tags:
- recurring_items
summary: Get a single recurring item
description: Retrieve the details of a specific recurring item with the
specified ID.
operationId: getRecurringById
parameters:
- name: id
in: path
description: ID of the recurring item to retrieve
required: true
schema:
type: integer
format: int32
examples:
tag:
summary: Example of a recurring ID
value: 994069
not found:
summary: Example of a recurring ID that does not exist
value: 543210
- name: start_date
in: query
schema:
type: string
format: date
description: Indicates the beginning of the range used to populate the
`matching` object in the recurring items. If omitted, the current
month will be used as the range.
Required if end_date exists.
- name: end_date
in: query
schema:
type: string
format: date
description: "Indicates the end of the range used to populate the
`matching` object in the recurring items. Required if start_date
exists. "
responses:
"200":
description: Recurring item object with the requested recurring item
ID
content:
application/json:
schema:
$ref: "#/components/schemas/recurringObject"
example:
id: 994069
description: Income
status: reviewed
transaction_criteria:
start_date: "2024-09-01"
end_date: "2024-10-31"
anchor_date: "2024-09-14"
granularity: month
quantity: 1
payee: Penny Lane
amount: "1250.8400"
to_base: 1250.84
currency: usd
plaid_account_id: 119806
manual_account_id: null
overrides:
payee: Paycheck
category_id: 88
matches:
request_start_date: "2024-10-01"
request_end_date: "2024-10-31"
expected_occurrence_dates:
- "2024-10-14"
- "2024-10-28"
found_transactions:
- date: "2024-10-14"
transaction_id: 2212150658
missing_transaction_dates:
- "2024-10-28"
created_by: 18328
created_at: "2024-07-28T01:01:38.716Z"
updated_at: "2024-07-28T01:01:38.716Z"
source: manual
"400":
description: Bad Request
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Request Validation Failure
errors:
- errMsg: must be a valid integer
instancePath: /query/ids/0
schemaPath: "#/properties/query/properties/ids/items/type"
keyword: type
params:
type: integer
"401":
$ref: "#/components/responses/unauthorizedToken"
"404":
description: Not Found
content:
application/json:
schema:
$ref: "#/components/schemas/errorResponseObject"
example:
message: Not Found
errors:
- errMsg: "There is no recurring item with the id: 543210."
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
/budgets/settings:
get:
tags:
- budgets
summary: Get budget period settings
description: |-
Returns budget period and display settings for the budget
associated with this API token.
These control how budget **periods** are calculated (granularity, anchor date, rollover, and related options). For general budget preferences such as currency and locale, see [/me/account/settings](#tag/me/GET/me/account/settings). operationId: getBudgetSettings responses: "200": description: Budget period settings for the current budget content: application/json: schema: $ref: "#/components/schemas/budgetSettingsResponseObject" "401": $ref: "#/components/responses/unauthorizedToken" "429": $ref: "#/components/responses/rateLimited" "500": $ref: "#/components/responses/serverError" /budgets: put: tags: - budgets summary: Upsert budget description: |- Create or update a budget for a category and period.
If a budget already exists for the specified `start_date` and `category_id`, the `amount` (and optional `currency` and `notes`) are updated; otherwise a new budget entry is created.
Note that `start_date` **must** be a valid budget period start for the account (based on the account's budget period settings). If an invalid `start_date` is provided, the request will fail with an error that indicates what the previous and next valid start dates are.
Use the [/budgets/settings](#tag/budgets/GET/budgets/settings) endpoint to view the budget period settings for the account.
To view details for existing budgets, use the [summary](#tag/summary) endpoint.
operationId: upsertBudget
requestBody:
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/upsertBudgetRequestObject"
example:
start_date: "2025-01-01"
category_id: 315177
amount: 500
currency: "usd"
notes: "Monthly groceries"
responses:
"200":
description: Budget upserted successfully
content:
application/json:
schema:
$ref: "#/components/schemas/budgetUpsertResponseObject"
example:
category_id: 315177
start_date: "2025-01-01"
amount: 500
currency: "usd"
to_base: 500.0
notes: "Monthly groceries"
"400":
description: Bad Request (invalid period start, invalid category, or
validation failure)
content:
application/json:
schema:
oneOf:
- $ref: "#/components/schemas/budgetInvalidPeriodErrorObject"
- $ref: "#/components/schemas/errorResponseObject"
examples:
invalid period:
summary: Start date not a valid budget period start
value:
message: Invalid Request
errors:
- errMsg: "The requested start date is not a valid budget period start for this account."
requested_start_date: "2025-01-15"
previous_valid_start_date: "2025-01-01"
next_valid_start_date: "2025-02-01"
validation error:
summary: Bad Category ID
value:
message: Invalid Request Body
errors:
- errMsg: "Category ID does not exist"
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
delete:
tags:
- budgets
summary: Delete budget
description: Removes the budget for the given category and period. If
there already is no budget set for that period, the request still
succeeds (idempotent).
Note that `start_date` **must** be a valid budget period start for the account (based on the account's budget period settings). If an invalid `start_date` is provided, the request will fail with an error that indicates what the previous and next valid start dates are.
Use the
[/budgets/settings](#tag/budgets/GET/budgets/settings) endpoint to view
the account's budget settings.
To view details for existing budgets,
use the [summary](#tag/summary) endpoint.
operationId: deleteBudget
parameters:
- in: query
name: category_id
required: true
description: Category ID of the budget to delete
schema:
type: integer
format: int32
- in: query
name: start_date
required: true
description: Start date of the budget period in ISO 8601 date format
(YYYY-MM-DD)
schema:
type: string
format: date
responses:
"204":
description: Budget deleted (or no budget existed for the given
category and period)
"400":
description: Bad Request (invalid period start, invalid category, or
validation failure)
content:
application/json:
schema:
oneOf:
- $ref: "#/components/schemas/budgetInvalidPeriodErrorObject"
- $ref: "#/components/schemas/errorResponseObject"
examples:
invalid period:
summary: Bad Category ID
value:
message: Invalid Request
errors:
- errMsg: "The requested start date is not a valid budget period start for this account."
requested_start_date: "2025-01-15"
previous_valid_start_date: "2025-01-01"
next_valid_start_date: "2025-02-01"
validation error:
summary: Invalid request body
value:
message: Invalid Request Body
errors:
- errMsg: "Category ID does not exist"
"401":
$ref: "#/components/responses/unauthorizedToken"
"429":
$ref: "#/components/responses/rateLimited"
"500":
$ref: "#/components/responses/serverError"
security:
- bearerSecurity: []
- cookieAuth: []