@lunch-money/developer-docs 2.11.1-preview.8 → 2.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,84 @@
1
+ # Documentation style guide
2
+
3
+ Use this guide for hand-written Markdown in `docs/` and `v2/docs/`. Preserve
4
+ intentional conventions in generated pages, the v1 Slate reference, and version
5
+ history entries.
6
+
7
+ ## Voice and structure
8
+
9
+ - Address the reader as “you” and use direct, practical language.
10
+ - Start with the reader's goal before introducing protocol or API details.
11
+ - Use one H1 per page and keep heading levels in logical order.
12
+ - Use sentence case for prose headings. Preserve official names, initialisms,
13
+ endpoint paths, property names, and exact UI labels.
14
+ - Add a next step when a guide belongs to a longer reader journey. Use
15
+ `## Need help?` only when the page provides support options.
16
+
17
+ ## Terminology
18
+
19
+ - Use “Lunch Money” for the product and “Lunchbag Labs, Inc.” only when the
20
+ legal company name is required.
21
+ - Use “Developer Portal,” “Developers page,” and “API reference” consistently.
22
+ Preserve different capitalization only for an exact UI label.
23
+ - Write “v1” and “v2” in prose. Use “V2 API” only where it is an established
24
+ proper label, such as the rendered reference title.
25
+ - Distinguish authentication from authorization, personal access tokens from
26
+ OAuth access tokens, and applications from their registered OAuth clients.
27
+
28
+ ## Code and placeholders
29
+
30
+ - Format endpoints, properties, headers, status codes, commands, filenames,
31
+ scope names, and literal values as code.
32
+ - Use `YOUR_ACCESS_TOKEN` as the generic access-token placeholder. Environment
33
+ variable examples may use `LUNCH_MONEY_ACCESS_TOKEN`.
34
+ - For equivalent multi-language examples, order tabs as JavaScript/Node.js,
35
+ Python, then cURL. Comparison tabs may follow the order that best teaches the
36
+ difference.
37
+ - Keep examples fictional and never include or request real credentials.
38
+
39
+ ## Callouts
40
+
41
+ Use the supported blockquote form:
42
+
43
+ ```markdown
44
+ > [!NOTE] Optional title
45
+ > Supporting content.
46
+ ```
47
+
48
+ - Use `NOTE` for context that affects understanding.
49
+ - Use `TIP` for optional advice or a more effective workflow.
50
+ - Use `WARNING` for credible security, privacy, data-loss, breaking-change, or
51
+ operational risk.
52
+ - Use sentence case for optional callout titles. Do not use HTML line breaks to
53
+ separate callout paragraphs.
54
+
55
+ ## Tabs
56
+
57
+ Use tabs when equivalent examples in multiple languages or a focused comparison
58
+ are easier to understand together:
59
+
60
+ ```markdown
61
+ :::tabs
62
+ @tab JavaScript/Node.js
63
+ JavaScript example
64
+
65
+ @tab Python
66
+ Python example
67
+ :::
68
+ ```
69
+
70
+ Use an `@tab` label for each panel and close the container with `:::`. For
71
+ equivalent language examples, order tabs as JavaScript/Node.js, Python, then
72
+ cURL. Comparison tabs may use the order that best teaches the difference.
73
+
74
+ ## Links and presentation
75
+
76
+ - Use canonical documentation paths from `manifest.json`. Keep aliases only for
77
+ compatibility; do not introduce new links to aliases.
78
+ - Use normal Markdown links for internal navigation. Keep HTML only when it adds
79
+ behavior Markdown cannot express, such as opening an external link in a new
80
+ tab.
81
+ - Avoid deeply nested headings, very wide tables, and long unbroken text that is
82
+ difficult to use in the constrained content column.
83
+ - Remove trailing whitespace and use blank lines, not `<br>`, for Markdown
84
+ structure unless a verified rendering requirement needs HTML.
@@ -1,4 +1,4 @@
1
- # Amounts & Balances
1
+ # Amounts & balances
2
2
 
3
3
  The Lunch Money API uses four properties — `amount`, `balance`, `currency`, and `to_base` — consistently across all objects that deal with money. Understanding how they work will help you build accurate, multi-currency-aware integrations.
4
4
 
@@ -24,7 +24,7 @@ Like `amount`, `balance` is always in the `currency` of the same object and foll
24
24
 
25
25
  ## `currency`
26
26
 
27
- `currency` is an ISO 4217 currency code (e.g., `"usd"`, `"eur"`, `"gbp"`). It is present on every object that carries an `amount` or `balance` and tells you what currency those values are in. See the [Supported Currencies guide](/v2/currencies) for the full list.
27
+ `currency` is an ISO 4217 currency code (e.g., `"usd"`, `"eur"`, `"gbp"`). It is present on every object that carries an `amount` or `balance` and tells you what currency those values are in. See the [Supported currencies guide](/currencies) for the full list.
28
28
 
29
29
  ## `to_base`
30
30
 
@@ -42,7 +42,7 @@ Like `amount`, `balance` is always in the `currency` of the same object and foll
42
42
  - Display amounts and balances in a single consistent currency across a multi-currency account
43
43
  - Perform arithmetic across transactions or accounts in different currencies
44
44
 
45
- ## Sign Convention
45
+ ## Sign convention
46
46
 
47
47
  ### Transaction amounts
48
48
 
@@ -70,10 +70,10 @@ A negative balance indicates the reversed state for that account type:
70
70
  - A savings account in overdraft has a negative `balance`
71
71
  - A credit card where the issuer owes you money (e.g., after a refund or overpayment) has a negative `balance`
72
72
 
73
- > [!NOTE] App Display Setting
73
+ > [!NOTE] App display setting
74
74
  > The Lunch Money app has a setting — **"Show Debits as Negative, Credits as Positive"** — that can flip how amounts are displayed in the UI. This setting is exposed in the API as `debits_as_negative` on the User object. **It has no effect on the API.** The API always returns positive values for debits and negative values for credits regardless of this setting. Apps may read `debits_as_negative` to match the user's preferred display format when showing amounts in their own UI.
75
75
 
76
- ## Exception: Budget and Summary Amounts
76
+ ## Exception: budget and summary amounts
77
77
 
78
78
  Budget objects and summary response objects don't use the transaction sign convention. Direction is conveyed by the **structure of the response** rather than the sign of the value — amounts are always positive magnitudes, and the object type or category flag tells you whether that activity is income or expense.
79
79
 
@@ -1,9 +1,9 @@
1
- # Branding your App
1
+ # Branding your app
2
2
 
3
3
  Building a tool, plugin, or integration on top of Lunch Money? Use the official **Powered by Lunch Money** badge to credit the connection clearly — without implying that your app *is* Lunch Money.
4
4
 
5
5
  <a href="https://lunchmoney.app/assets/images/media-kit/powered-by-lunch-money-badge.png" download="powered-by-lunch-money-badge.png" target="_blank" rel="noopener noreferrer" title="Download Powered by Lunch Money badge">
6
- <img src="/v2/images/powered-by-lunch-money-badge.png" alt="Powered by Lunch Money badge" />
6
+ <img src="/v2/images/powered-by-lunch-money-badge.png" alt="Powered by Lunch Money badge" width="320" />
7
7
  </a>
8
8
 
9
9
  > [!TIP]
@@ -1,15 +1,15 @@
1
- # Supported Currencies
1
+ # Supported currencies
2
2
 
3
3
  Lunch Money supports a wide range of currencies for transactions and accounts. All currency values in the API use three-letter lowercase currency codes in ISO 4217 format.
4
4
 
5
- ## Currency Code Format
5
+ ## Currency code format
6
6
 
7
7
  Currency codes must be:
8
8
  - Three letters
9
9
  - Lowercase
10
10
  - Valid ISO 4217 currency codes
11
11
 
12
- ## Supported Currencies
12
+ ## Supported currencies
13
13
 
14
14
  The following currencies are currently supported in Lunch Money:
15
15
 
@@ -183,7 +183,7 @@ The following currencies are currently supported in Lunch Money:
183
183
  | `zmw` | Zambian Kwacha |
184
184
  | `zwl` | Zimbabwean Dollar |
185
185
 
186
- ## Using Currencies in the API
186
+ ## Using currencies in the API
187
187
 
188
188
  When creating or updating transactions, accounts, or other resources that include currency information, use the three-letter lowercase currency code:
189
189
 
@@ -247,11 +247,11 @@ curl -X POST 'https://api.lunchmoney.dev/v2/transactions' \
247
247
  ```
248
248
  :::
249
249
 
250
- ## Default Currency
250
+ ## Default currency
251
251
 
252
252
  If you don't specify a currency when creating a transaction or account, Lunch Money will default to your account's primary currency. You can check your primary currency by calling the `GET /v2/me` endpoint.
253
253
 
254
- ## Currency Validation
254
+ ## Currency validation
255
255
 
256
256
  The API validates that currency codes match the supported list. If you provide an unsupported currency code, you'll receive a validation error:
257
257
 
@@ -268,10 +268,9 @@ The API validates that currency codes match the supported list. If you provide a
268
268
  }
269
269
  ```
270
270
 
271
- ## Requesting New Currencies
271
+ ## Requesting new currencies
272
272
 
273
273
  If your currency is missing from the supported list, please let us know via email at [support@lunchmoney.app](mailto:support@lunchmoney.app) and we'll work on getting it added.
274
274
 
275
- > [!NOTE] Currency Support
275
+ > [!NOTE] Currency support
276
276
  > Currency support is continuously expanding. If you need a currency that's not currently listed, reach out to our support team and we'll prioritize adding it.
277
-
@@ -1,14 +1,14 @@
1
- # Getting Started with the API
1
+ # Getting started with the API
2
2
 
3
3
  Welcome to the Lunch Money developer API! This API has enabled the Lunch Money user community to build a broad set of tools and plug-ins to complement their Lunch Money experience and help other users. This guide will help you get started using the Lunch Money API.
4
4
 
5
5
  Most users interact with their Lunch Money data using the official web or mobile app. Making API calls is another way to interact with your Lunch Money data. You can make API calls that **get** your data for you, allowing you to do other things with it, like generating your own charts or simply archiving your data. You can also make API calls that **change** or **delete** your data. Any changes you make are permanent, just like they would be if you made changes using the web or mobile app.
6
6
 
7
7
  > [!WARNING]
8
- > Changes made via the API are permanent and cannot be undone!<br> Always use a test budget when getting started.
8
+ > Changes made via the API are permanent and cannot be undone. Always use a test budget when getting started.
9
9
 
10
10
 
11
- ## Create a Test Budgeting Account
11
+ ## Create a test budgeting account
12
12
 
13
13
  Since changes to your data made by the API are permanent, the best way to begin interacting with the API is to <a href="https://support.lunchmoney.app/miscellaneous/unlimited-budgeting-accounts" target="_blank" rel="noopener noreferrer">create a new test budgeting account</a> in your existing Lunch Money account. As you start using the API, you can interact with this test account and ensure that your real data is not modified.
14
14
 
@@ -49,7 +49,7 @@ After you do this, the web page will show you a long alphanumeric string. This i
49
49
  Congratulations! You've got an access token and are ready to make an API request! Later, when you are more comfortable with the API, you can repeat this process to create a new access token associated with your real budget.
50
50
 
51
51
  > [!WARNING]
52
- > Treat your access tokens like passwords.<br>Don't share them with anyone that you don't trust.
52
+ > Treat your access tokens like passwords. Don't share them with anyone you don't trust.
53
53
 
54
54
  If you ever worry that your access token has been compromised, you can always come back to the Developers page and hit the Revoke button.
55
55
 
@@ -63,21 +63,21 @@ When you start to write code that makes API calls, you will need to include this
63
63
 
64
64
  ```bash
65
65
  curl --location 'https://api.lunchmoney.dev/v2/me' \
66
- --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>'
66
+ --header 'Authorization: Bearer YOUR_ACCESS_TOKEN'
67
67
  ```
68
68
 
69
- If this doesn't make sense yet, that's OK!
69
+ If this doesn't make sense yet, that's OK!
70
70
 
71
- There is an easier way to use your access token to make requests. Head over to the [API Reference Documentation](/v2/docs).
71
+ There is an easier way to use your access token to make requests. Head over to the [API Reference Documentation](/v2/docs).
72
72
 
73
73
  :::tabs
74
74
 
75
75
  @tab 1. Supply Your Token
76
- Paste your new token into the box that says "Bearer Token" in the server configuration in the upper right hand corner.
76
+ Paste your new token into the box that says "Bearer Token" in the server configuration in the upper right hand corner.
77
77
  ![Bearer Token](/images/PasteBearer.png)
78
78
 
79
79
  @tab 2. Make a Test Request
80
- Scroll down to the section called "Get Current User" and hit the "Test Request" button.
80
+ Scroll down to the section called "Get Current User" and hit the "Test Request" button.
81
81
  ![TestRequest.png](/images/TestRequest.png)
82
82
  :::
83
83
 
@@ -85,14 +85,14 @@ This will pop up a dialog box that you can use to send an API request. This is a
85
85
 
86
86
  From here, you can explore the rest of the Lunch Money API and start thinking about what you might do with it.
87
87
 
88
- ## What Can You Build?
88
+ ## What can you build?
89
89
 
90
90
  The Lunch Money community has already built a wide variety of tools — automations, importers, dashboards, and more. Check out the <a href="https://lunchmoney.app/developers#community-projects" target="_blank" rel="noopener noreferrer">Developer Tools & Community Projects</a> list for inspiration, or drop by the <a href="https://discord.com/channels/842337014556262411/1134597088504729780" target="_blank" rel="noopener noreferrer">Show and Tell channel</a> on Discord to see what others are sharing.
91
91
 
92
92
  > [!NOTE]
93
93
  > Built something with the API? Let us know and we'll add it to the list!
94
94
 
95
- ## I still need help!
95
+ ## Need help?
96
96
 
97
97
  If you still aren't sure how to get started, we have other resources to help.
98
98
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Welcome to the Lunch Money developer documentation. This site covers the **v2 API** — the current generation of the Lunch Money API — along with guides, a reference for the legacy v1 API, and tools for exploring the API without touching real data.
4
4
 
5
- ## Getting Started
5
+ ## Getting started
6
6
 
7
7
  The v2 API is available at:
8
8
 
@@ -16,9 +16,9 @@ Get your access token from the <a href="https://my.lunchmoney.app/developers" ta
16
16
  Authorization: Bearer YOUR_ACCESS_TOKEN
17
17
  ```
18
18
 
19
- See the [Getting Started guide](/v2/getting-started) for a full walkthrough, including how to create a test budget and make your first request.
19
+ See the [Getting started guide](/getting-started) for a full walkthrough, including how to create a test budget and make your first request.
20
20
 
21
- ## Trying the API Without Real Data
21
+ ## Trying the API without real data
22
22
 
23
23
  The <a href="/v2/docs">interactive API reference</a> lets you make live API requests directly from the documentation — including a **static mock server** you can use to explore the API without an access token or any risk to real data.
24
24
 
@@ -34,7 +34,7 @@ Set your Bearer Token to any string of **11 or more characters** — no real tok
34
34
 
35
35
  :::
36
36
 
37
- ## Client Libraries & SDKs
37
+ ## Client libraries & SDKs
38
38
 
39
39
  An official **TypeScript SDK** is available:
40
40
  - NPM: <a href="https://www.npmjs.com/package/@lunch-money/v2-api-spec" target="_blank" rel="noopener noreferrer">`@lunch-money/v2-api-spec`</a>
@@ -58,6 +58,6 @@ Join the conversation in the <a href="https://lunchmoney.app/discord" target="_b
58
58
 
59
59
  **Useful links:**
60
60
  - <a href="/v2/docs">Interactive API Reference</a>
61
- - [Getting Started Guide](/v2/getting-started)
61
+ - [Getting started guide](/getting-started)
62
62
  - <a href="https://github.com/lunch-money/awesome-lunchmoney" target="_blank" rel="noopener noreferrer">Awesome Lunch Money Projects</a>
63
63
  - [Contact: devsupport@lunchmoney.app](mailto:devsupport@lunchmoney.app)
package/docs/locales.md CHANGED
@@ -1,4 +1,4 @@
1
- # Supported Locales
1
+ # Supported locales
2
2
 
3
3
  Lunch Money uses locale tags to format numbers and currency amounts in the web
4
4
  and mobile apps. Date presentation is controlled separately by the user-level
@@ -10,14 +10,14 @@ currency symbol or code placement and rendering. It does not change the
10
10
  account's selected currency, numeric values, or the representation of dates,
11
11
  numbers, and amounts in API responses.
12
12
 
13
- ## Locale Tag Format
13
+ ## Locale tag format
14
14
 
15
15
  Each supported value combines a language code and a region code, separated by a
16
16
  hyphen. For example, `en-US` selects English formatting conventions for the
17
17
  United States, while `en-GB` selects English formatting conventions for the
18
18
  United Kingdom.
19
19
 
20
- ## Supported Locales
20
+ ## Supported locales
21
21
 
22
22
  The examples format `123456789` as USD. An account's primary currency determines
23
23
  the currency symbol and number of fraction digits. Exact spacing and symbol
@@ -111,7 +111,7 @@ implementation.
111
111
  | `uk-UA` | Ukrainian | Ukraine | `123 456 789,00 USD` |
112
112
  | `vi-VN` | Vietnamese | Vietnam | `123.456.789,00 US$` |
113
113
 
114
- ## Legacy Locale Tags
114
+ ## Legacy locale tags
115
115
 
116
116
  The supported list retains two legacy language codes for compatibility:
117
117
 
@@ -6,10 +6,10 @@ The Lunch Money API uses offset-based pagination for the `GET /transactions` end
6
6
 
7
7
  When retrieving transactions using `GET /transactions`, the API supports pagination through the `limit` and `offset` query parameters. By default, the endpoint returns up to 1000 transactions per request. If more transactions match your filter criteria, the response includes a `has_more` property set to `true`, indicating that additional pages are available.
8
8
 
9
- > [!NOTE] Pagination Scope
9
+ > [!NOTE] Pagination scope
10
10
  > Pagination works with all filter parameters including date ranges, account IDs, categories, tags, and status filters. The pagination applies to the filtered result set.
11
11
 
12
- ## How Pagination Works
12
+ ## How pagination works
13
13
 
14
14
  ### Parameters
15
15
 
@@ -24,13 +24,13 @@ When retrieving transactions using `GET /transactions`, the API supports paginat
24
24
  - Minimum: `0`
25
25
  - Use this to fetch subsequent pages of results
26
26
 
27
- ### Response Property
27
+ ### Response property
28
28
 
29
29
  - **`has_more`**: A boolean property in the response indicating whether more transactions are available
30
30
  - `true`: More transactions match your filter criteria and are available on subsequent pages
31
31
  - `false`: All matching transactions have been returned
32
32
 
33
- ### Basic Pagination Flow
33
+ ### Basic pagination flow
34
34
 
35
35
  1. Make your first request (optionally with `limit` specified, defaults to 1000)
36
36
  2. Check the `has_more` property in the response
@@ -39,7 +39,7 @@ When retrieving transactions using `GET /transactions`, the API supports paginat
39
39
 
40
40
  ## Examples
41
41
 
42
- ### Basic Pagination
42
+ ### Basic pagination
43
43
 
44
44
  Here's how to fetch transactions page by page:
45
45
 
@@ -61,10 +61,10 @@ async function getAllTransactions(accessToken, limit = 1000) {
61
61
 
62
62
  const data = await response.json();
63
63
  allTransactions.push(...data.transactions);
64
-
64
+
65
65
  hasMore = data.has_more;
66
66
  offset += limit;
67
-
67
+
68
68
  console.log(`Fetched ${data.transactions.length} transactions (total: ${allTransactions.length})`);
69
69
  }
70
70
 
@@ -84,22 +84,22 @@ def get_all_transactions(access_token, limit=1000):
84
84
  all_transactions = []
85
85
  offset = 0
86
86
  has_more = True
87
-
87
+
88
88
  headers = {
89
89
  'Authorization': f'Bearer {access_token}'
90
90
  }
91
-
91
+
92
92
  while has_more:
93
93
  url = f'https://api.lunchmoney.dev/v2/transactions?limit={limit}&offset={offset}'
94
94
  response = requests.get(url, headers=headers)
95
95
  data = response.json()
96
-
96
+
97
97
  all_transactions.extend(data['transactions'])
98
98
  has_more = data['has_more']
99
99
  offset += limit
100
-
100
+
101
101
  print(f"Fetched {len(data['transactions'])} transactions (total: {len(all_transactions)})")
102
-
102
+
103
103
  return all_transactions
104
104
 
105
105
  # Usage
@@ -119,18 +119,18 @@ ALL_TRANSACTIONS="[]"
119
119
 
120
120
  while [ "$HAS_MORE" = "true" ]; do
121
121
  echo "Fetching transactions with offset=$OFFSET, limit=$LIMIT..."
122
-
122
+
123
123
  RESPONSE=$(curl -s -X GET \
124
124
  "https://api.lunchmoney.dev/v2/transactions?limit=$LIMIT&offset=$OFFSET" \
125
125
  -H "Authorization: Bearer $ACCESS_TOKEN")
126
-
126
+
127
127
  TRANSACTIONS=$(echo $RESPONSE | jq -r '.transactions')
128
128
  HAS_MORE=$(echo $RESPONSE | jq -r '.has_more')
129
-
129
+
130
130
  # Merge transactions (simplified - in practice you'd want proper JSON merging)
131
131
  COUNT=$(echo $TRANSACTIONS | jq 'length')
132
132
  echo "Fetched $COUNT transactions"
133
-
133
+
134
134
  OFFSET=$((OFFSET + LIMIT))
135
135
  done
136
136
 
@@ -138,7 +138,7 @@ echo "All transactions fetched"
138
138
  ```
139
139
  :::
140
140
 
141
- ### Pagination with Date Filters
141
+ ### Pagination with date filters
142
142
 
143
143
  Pagination works seamlessly with date range filters:
144
144
 
@@ -166,7 +166,7 @@ async function getTransactionsByDateRange(accessToken, startDate, endDate) {
166
166
 
167
167
  const data = await response.json();
168
168
  allTransactions.push(...data.transactions);
169
-
169
+
170
170
  hasMore = data.has_more;
171
171
  offset += limit;
172
172
  }
@@ -192,9 +192,9 @@ def get_transactions_by_date_range(access_token, start_date, end_date):
192
192
  offset = 0
193
193
  has_more = True
194
194
  limit = 1000
195
-
195
+
196
196
  headers = {'Authorization': f'Bearer {access_token}'}
197
-
197
+
198
198
  while has_more:
199
199
  params = {
200
200
  'start_date': start_date,
@@ -202,15 +202,15 @@ def get_transactions_by_date_range(access_token, start_date, end_date):
202
202
  'limit': limit,
203
203
  'offset': offset
204
204
  }
205
-
205
+
206
206
  url = f"https://api.lunchmoney.dev/v2/transactions?{urlencode(params)}"
207
207
  response = requests.get(url, headers=headers)
208
208
  data = response.json()
209
-
209
+
210
210
  all_transactions.extend(data['transactions'])
211
211
  has_more = data['has_more']
212
212
  offset += limit
213
-
213
+
214
214
  return all_transactions
215
215
 
216
216
  # Usage: Get all transactions for January 2024
@@ -236,17 +236,17 @@ while [ "$HAS_MORE" = "true" ]; do
236
236
  RESPONSE=$(curl -s -X GET \
237
237
  "https://api.lunchmoney.dev/v2/transactions?start_date=$START_DATE&end_date=$END_DATE&limit=$LIMIT&offset=$OFFSET" \
238
238
  -H "Authorization: Bearer $ACCESS_TOKEN")
239
-
239
+
240
240
  HAS_MORE=$(echo $RESPONSE | jq -r '.has_more')
241
241
  COUNT=$(echo $RESPONSE | jq -r '.transactions | length')
242
242
  echo "Fetched $COUNT transactions (offset=$OFFSET)"
243
-
243
+
244
244
  OFFSET=$((OFFSET + LIMIT))
245
245
  done
246
246
  ```
247
247
  :::
248
248
 
249
- ### Handling the `has_more` Flag
249
+ ### Handling the `has_more` flag
250
250
 
251
251
  Always check the `has_more` property to determine if you need to fetch more pages:
252
252
 
@@ -262,7 +262,7 @@ async function fetchTransactionsPage(accessToken, limit = 1000, offset = 0) {
262
262
  });
263
263
 
264
264
  const data = await response.json();
265
-
265
+
266
266
  return {
267
267
  transactions: data.transactions,
268
268
  hasMore: data.has_more,
@@ -288,10 +288,10 @@ import requests
288
288
  def fetch_transactions_page(access_token, limit=1000, offset=0):
289
289
  url = f'https://api.lunchmoney.dev/v2/transactions?limit={limit}&offset={offset}'
290
290
  headers = {'Authorization': f'Bearer {access_token}'}
291
-
291
+
292
292
  response = requests.get(url, headers=headers)
293
293
  data = response.json()
294
-
294
+
295
295
  return {
296
296
  'transactions': data['transactions'],
297
297
  'has_more': data['has_more'],
@@ -335,9 +335,9 @@ fi
335
335
  ```
336
336
  :::
337
337
 
338
- ## Best Practices
338
+ ## Best practices
339
339
 
340
- ### 1. Use Appropriate Limit Values
340
+ ### 1. Use appropriate limit values
341
341
 
342
342
  Choose a `limit` value that balances performance and number of requests:
343
343
 
@@ -353,7 +353,7 @@ const response = await fetch('/v2/transactions?limit=1000');
353
353
  const response = await fetch('/v2/transactions?limit=500');
354
354
  ```
355
355
 
356
- ### 2. Always Check `has_more`
356
+ ### 2. Always check `has_more`
357
357
 
358
358
  Don't assume you've received all results. Always check the `has_more` property:
359
359
 
@@ -375,7 +375,7 @@ while (hasMore) {
375
375
  }
376
376
  ```
377
377
 
378
- ### 3. Combine with Date Ranges When Possible
378
+ ### 3. Combine with date ranges when possible
379
379
 
380
380
  If you know the date range you need, use `start_date` and `end_date` parameters to reduce the result set size:
381
381
 
@@ -387,12 +387,12 @@ const response = await fetch(
387
387
 
388
388
  // ❌ Less efficient: Fetches all transactions then filters client-side
389
389
  const allTransactions = await fetchAllTransactions();
390
- const janTransactions = allTransactions.filter(t =>
390
+ const janTransactions = allTransactions.filter(t =>
391
391
  t.date >= '2024-01-01' && t.date <= '2024-01-31'
392
392
  );
393
393
  ```
394
394
 
395
- ### 4. Handle Edge Cases
395
+ ### 4. Handle edge cases
396
396
 
397
397
  - **Empty results**: The `transactions` array will be empty, and `has_more` will be `false`
398
398
  - **Exact page boundary**: If the number of results is exactly divisible by your limit, `has_more` will be `false` on the last page
@@ -406,24 +406,24 @@ async function safeFetchTransactions(accessToken, limit = 1000, offset = 0) {
406
406
  headers: { 'Authorization': `Bearer ${accessToken}` }
407
407
  }
408
408
  );
409
-
409
+
410
410
  if (!response.ok) {
411
411
  throw new Error(`API error: ${response.status}`);
412
412
  }
413
-
413
+
414
414
  const data = await response.json();
415
-
415
+
416
416
  // Handle empty results
417
417
  if (data.transactions.length === 0 && !data.has_more) {
418
418
  console.log('No transactions found');
419
419
  return [];
420
420
  }
421
-
421
+
422
422
  return data;
423
423
  }
424
424
  ```
425
425
 
426
- ### 5. Implement Rate Limit Awareness
426
+ ### 5. Implement rate limit awareness
427
427
 
428
428
  When paginating through many pages, be mindful of rate limits. Consider adding delays between requests:
429
429
 
@@ -439,7 +439,7 @@ async function getAllTransactionsWithRateLimit(accessToken) {
439
439
  allTransactions.push(...data.transactions);
440
440
  hasMore = data.has_more;
441
441
  offset += limit;
442
-
442
+
443
443
  // Small delay to avoid hitting rate limits
444
444
  if (hasMore) {
445
445
  await new Promise(resolve => setTimeout(resolve, 100));
@@ -452,7 +452,7 @@ async function getAllTransactionsWithRateLimit(accessToken) {
452
452
 
453
453
  ## Troubleshooting
454
454
 
455
- ### Common Issues
455
+ ### Common issues
456
456
 
457
457
  **Issue**: Getting duplicate transactions across pages
458
458
 
@@ -506,7 +506,7 @@ const data = await fetch('/v2/transactions?start_date=2024-01-01&end_date=2024-0
506
506
  // data.transactions.length might be 200, and has_more will be false
507
507
  ```
508
508
 
509
- ## Need Help?
509
+ ## Need help?
510
510
 
511
511
  If you're experiencing pagination issues that can't be resolved through the techniques described above:
512
512
 
@@ -514,4 +514,3 @@ If you're experiencing pagination issues that can't be resolved through the tech
514
514
  - Verify that you're checking the `has_more` property on each response
515
515
  - Consider using date range filters to reduce the result set size
516
516
  - [Email our developer advocate](mailto:jp@lunchmoney.app) if you need assistance with pagination implementation
517
-
@@ -1,4 +1,4 @@
1
- # Rate Limiting
1
+ # Rate limiting
2
2
 
3
3
  The Lunch Money API implements rate limiting to ensure fair usage and prevent abuse of API resources. This guide explains how rate limiting works and how to monitor your rate limit status using response headers.
4
4
 
@@ -9,20 +9,20 @@ Rate limiting is applied to all requests to the `/v1/` and `/v2/` endpoints and
9
9
 
10
10
  If you exceed this limit, you will receive a `429 Too Many Requests` response.
11
11
 
12
- > [!NOTE] Rate Limit Scope
12
+ > [!NOTE] Rate limit scope
13
13
  > Rate limiting is applied per IP address. Requests from the same IP address share the same rate limit quotas.
14
14
 
15
- ## Rate Limit Response
15
+ ## Rate limit response
16
16
 
17
17
  When you exceed a rate limit, the API returns a `429 Too Many Requests` response:
18
18
 
19
- ### HTTP Status Code
19
+ ### HTTP status code
20
20
 
21
21
  ```
22
22
  429 Too Many Requests
23
23
  ```
24
24
 
25
- ### Response Body
25
+ ### Response body
26
26
 
27
27
  The response body follows the standard v2 error format:
28
28
 
@@ -37,11 +37,11 @@ The response body follows the standard v2 error format:
37
37
  }
38
38
  ```
39
39
 
40
- ### Response Headers
40
+ ### Response headers
41
41
 
42
42
  The API includes rate limit information in response headers for all requests (both successful and rate-limited). You can inspect these headers to monitor your current rate limit status and determine when you can make additional requests.
43
43
 
44
- #### Standard Headers (RFC Draft 7)
44
+ #### Standard headers (RFC Draft 7)
45
45
 
46
46
  The API includes standard rate limit headers in all responses:
47
47
 
@@ -56,12 +56,12 @@ RateLimit-Remaining: 3
56
56
  RateLimit-Reset: 1704067200
57
57
  ```
58
58
 
59
- #### Legacy Headers
59
+ #### Legacy headers
60
60
 
61
61
  For backward compatibility, the API also includes legacy `X-RateLimit-*` headers:
62
62
 
63
63
  - **`X-RateLimit-Limit`**: The maximum number of requests allowed per window
64
- - **`X-RateLimit-Remaining`**: The number of requests remaining in the current window
64
+ - **`X-RateLimit-Remaining`**: The number of requests remaining in the current window
65
65
  - **`X-RateLimit-Reset`**: The time (in seconds since Unix epoch) when the rate limit window resets
66
66
 
67
67
  Example headers:
@@ -71,7 +71,7 @@ X-RateLimit-Remaining: 3
71
71
  X-RateLimit-Reset: 1704067200
72
72
  ```
73
73
 
74
- #### Retry-After Header
74
+ #### `Retry-After` header
75
75
 
76
76
  When you receive a `429 Too Many Requests` response, the API includes a `Retry-After` header indicating how many seconds you should wait before retrying:
77
77
 
@@ -81,12 +81,12 @@ Retry-After: 45
81
81
 
82
82
  This value represents the time until the rate limit window resets (rounded up to the nearest second).
83
83
 
84
- > [!TIP] Using Retry-After
84
+ > [!TIP] Using `Retry-After`
85
85
  > Always respect the `Retry-After` header value when implementing retry logic. Waiting for the specified duration ensures you don't waste requests on premature retries.
86
86
 
87
- ## Monitoring Rate Limits
87
+ ## Monitoring rate limits
88
88
 
89
- ### Reading Rate Limit Headers
89
+ ### Reading rate limit headers
90
90
 
91
91
  You can monitor your rate limit status by inspecting the headers in every API response, even successful ones. This allows you to proactively slow down your request rate before hitting the limit.
92
92
 
@@ -95,12 +95,12 @@ You can monitor your rate limit status by inspecting the headers in every API re
95
95
  ```javascript
96
96
  async function makeRequest(url, options) {
97
97
  const response = await fetch(url, options);
98
-
98
+
99
99
  // Check rate limit status from headers
100
100
  const remaining = parseInt(response.headers.get('X-RateLimit-Remaining') || '0');
101
101
  const limit = parseInt(response.headers.get('X-RateLimit-Limit') || '0');
102
102
  const resetTime = parseInt(response.headers.get('X-RateLimit-Reset') || '0');
103
-
103
+
104
104
  if (remaining < 5) {
105
105
  console.warn(`Rate limit warning: ${remaining}/${limit} requests remaining`);
106
106
  const waitTime = resetTime - Math.floor(Date.now() / 1000);
@@ -108,13 +108,13 @@ async function makeRequest(url, options) {
108
108
  console.log(`Rate limit resets in ${waitTime} seconds`);
109
109
  }
110
110
  }
111
-
111
+
112
112
  if (response.status === 429) {
113
113
  const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
114
114
  console.error(`Rate limited! Retry after ${retryAfter} seconds`);
115
115
  throw new Error(`Rate limited: retry after ${retryAfter}s`);
116
116
  }
117
-
117
+
118
118
  return response;
119
119
  }
120
120
  ```
@@ -126,23 +126,23 @@ import time
126
126
 
127
127
  def make_request(url, headers):
128
128
  response = requests.get(url, headers=headers)
129
-
129
+
130
130
  # Check rate limit status
131
131
  remaining = int(response.headers.get('X-RateLimit-Remaining', 0))
132
132
  limit = int(response.headers.get('X-RateLimit-Limit', 0))
133
133
  reset_time = int(response.headers.get('X-RateLimit-Reset', 0))
134
-
134
+
135
135
  if remaining < 5:
136
136
  print(f"Rate limit warning: {remaining}/{limit} requests remaining")
137
137
  wait_time = reset_time - int(time.time())
138
138
  if wait_time > 0:
139
139
  print(f"Rate limit resets in {wait_time} seconds")
140
-
140
+
141
141
  if response.status_code == 429:
142
142
  retry_after = int(response.headers.get('Retry-After', 60))
143
143
  print(f"Rate limited! Retry after {retry_after} seconds")
144
144
  raise Exception(f"Rate limited: retry after {retry_after}s")
145
-
145
+
146
146
  return response
147
147
  ```
148
148
 
@@ -150,7 +150,7 @@ def make_request(url, headers):
150
150
  ```bash
151
151
  # Make a request and capture headers
152
152
  response=$(curl -s -D /tmp/headers.txt -o /tmp/body.txt -w "%{http_code}" \
153
- -H "Authorization: Bearer YOUR_TOKEN" \
153
+ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
154
154
  "https://api.lunchmoney.dev/v2/me")
155
155
 
156
156
  # Extract rate limit headers
@@ -170,7 +170,7 @@ fi
170
170
  ```
171
171
  :::
172
172
 
173
- ### Implementing Exponential Backoff
173
+ ### Implementing exponential backoff
174
174
 
175
175
  When you receive a `429` response, implement exponential backoff with jitter to avoid overwhelming the API:
176
176
 
@@ -178,28 +178,28 @@ When you receive a `429` response, implement exponential backoff with jitter to
178
178
  async function makeRequestWithRetry(url, options, maxRetries = 3) {
179
179
  for (let attempt = 0; attempt < maxRetries; attempt++) {
180
180
  const response = await fetch(url, options);
181
-
181
+
182
182
  if (response.status !== 429) {
183
183
  return response;
184
184
  }
185
-
185
+
186
186
  // Get retry-after header or use exponential backoff
187
187
  const retryAfter = parseInt(response.headers.get('Retry-After') || '0');
188
- const waitTime = retryAfter > 0
188
+ const waitTime = retryAfter > 0
189
189
  ? retryAfter * 1000 // Convert seconds to milliseconds
190
190
  : Math.min(1000 * Math.pow(2, attempt) + Math.random() * 1000, 30000);
191
-
191
+
192
192
  console.log(`Rate limited. Waiting ${waitTime}ms before retry ${attempt + 1}/${maxRetries}`);
193
193
  await new Promise(resolve => setTimeout(resolve, waitTime));
194
194
  }
195
-
195
+
196
196
  throw new Error('Max retries exceeded due to rate limiting');
197
197
  }
198
198
  ```
199
199
 
200
- ## Best Practices
200
+ ## Best practices
201
201
 
202
- ### 1. Monitor Headers Proactively
202
+ ### 1. Monitor headers proactively
203
203
 
204
204
  Don't wait for a `429` response. Check rate limit headers on every request and adjust your request rate accordingly:
205
205
 
@@ -211,7 +211,7 @@ if (remaining < threshold) {
211
211
  }
212
212
  ```
213
213
 
214
- ### 2. Implement Request Queuing
214
+ ### 2. Implement request queuing
215
215
 
216
216
  For applications that need to make many requests, implement a queue system that respects rate limits:
217
217
 
@@ -222,14 +222,14 @@ class RateLimitedQueue {
222
222
  this.remaining = 100; // Start with max
223
223
  this.resetTime = Date.now() + (15 * 60 * 1000);
224
224
  }
225
-
225
+
226
226
  async enqueue(requestFn) {
227
227
  return new Promise((resolve, reject) => {
228
228
  this.queue.push({ requestFn, resolve, reject });
229
229
  this.processQueue();
230
230
  });
231
231
  }
232
-
232
+
233
233
  async processQueue() {
234
234
  if (this.queue.length === 0 || this.remaining <= 0) {
235
235
  if (this.remaining <= 0 && this.resetTime > Date.now()) {
@@ -238,15 +238,15 @@ class RateLimitedQueue {
238
238
  }
239
239
  return;
240
240
  }
241
-
241
+
242
242
  const { requestFn, resolve, reject } = this.queue.shift();
243
243
  try {
244
244
  const response = await requestFn();
245
-
245
+
246
246
  // Update rate limit status from headers
247
247
  this.remaining = parseInt(response.headers.get('X-RateLimit-Remaining') || '0');
248
248
  this.resetTime = parseInt(response.headers.get('X-RateLimit-Reset') || '0') * 1000;
249
-
249
+
250
250
  resolve(response);
251
251
  this.processQueue(); // Process next item
252
252
  } catch (error) {
@@ -256,7 +256,7 @@ class RateLimitedQueue {
256
256
  }
257
257
  ```
258
258
 
259
- ### 3. Cache Responses When Possible
259
+ ### 3. Cache responses when possible
260
260
 
261
261
  Reduce the number of API calls by caching responses locally:
262
262
 
@@ -267,24 +267,24 @@ const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
267
267
  async function getCachedRequest(url, options) {
268
268
  const cacheKey = `${url}:${JSON.stringify(options)}`;
269
269
  const cached = cache.get(cacheKey);
270
-
270
+
271
271
  if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
272
272
  return cached.data;
273
273
  }
274
-
274
+
275
275
  const response = await fetch(url, options);
276
276
  const data = await response.json();
277
-
277
+
278
278
  cache.set(cacheKey, {
279
279
  data,
280
280
  timestamp: Date.now()
281
281
  });
282
-
282
+
283
283
  return data;
284
284
  }
285
285
  ```
286
286
 
287
- ### 4. Batch Operations When Available
287
+ ### 4. Batch operations when available
288
288
 
289
289
  Use bulk endpoints when available to reduce the number of requests:
290
290
 
@@ -309,7 +309,7 @@ await fetch('/v2/categories', {
309
309
  ```
310
310
  :::
311
311
 
312
- ### 5. Limit Crypto Refresh Polling
312
+ ### 5. Limit crypto refresh polling
313
313
 
314
314
  Crypto refresh requests can be bursty if you poll too often. For `POST /v2/crypto/synced/{id}/refresh`:
315
315
 
@@ -319,14 +319,14 @@ Crypto refresh requests can be bursty if you poll too often. For `POST /v2/crypt
319
319
 
320
320
  ## Troubleshooting
321
321
 
322
- ### Common Issues
322
+ ### Common issues
323
323
 
324
324
  **Issue**: Rate limits resetting unexpectedly
325
325
 
326
326
  **Solution**: Rate limits are tracked per IP address. If you're behind a proxy or load balancer, multiple clients may share the same IP and exhaust the shared quota.
327
327
 
328
328
 
329
- ## Need Help?
329
+ ## Need help?
330
330
 
331
331
  If you're experiencing rate limiting issues that can't be resolved through the techniques described above:
332
332
 
@@ -73,7 +73,7 @@ const token = process.env.LUNCH_MONEY_ACCESS_TOKEN;
73
73
  > [!WARNING]
74
74
  > Avoid pasting your access token directly into an AI chat window. Treat it like a password — store it in an environment variable, a `.env` file excluded from source control, or your operating system's secret store.
75
75
 
76
- ## Best Practices
76
+ ## Best practices
77
77
 
78
78
  1. **Start with a test budget** — API changes are permanent. Use a test budget while you're learning so your real data stays safe. See the [Getting Started guide](/getting-started) for instructions.
79
79
 
@@ -97,7 +97,7 @@ If you want to experiment, here are a few low-risk starting points:
97
97
 
98
98
  Start small, and use a test budget while you're learning.
99
99
 
100
- ## Need Help?
100
+ ## Need help?
101
101
 
102
102
  - Join the <a href="https://lunchmoney.app/discord" target="_blank" rel="noopener noreferrer">Lunch Money Discord</a> and ask in the **#developer-api** channel
103
103
  - [Email our developer advocate](mailto:jp@lunchmoney.app)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunch-money/developer-docs",
3
- "version": "2.11.1-preview.8",
3
+ "version": "2.11.1",
4
4
  "description": "Developer documentation content for Lunch Money APIs",
5
5
  "exports": {
6
6
  ".": "./package.json",
@@ -1,4 +1,4 @@
1
- # v2 API Overview
1
+ # v2 API overview
2
2
 
3
3
  Welcome to the Lunch Money v2 API. This page covers the core concepts you need to work with the API effectively — authentication, response shapes, naming conventions, error handling, and more. If you're migrating from v1, see the [Migration Guide](./migration-guide.md).
4
4
 
@@ -10,7 +10,7 @@ All API requests require a Bearer token in the `Authorization` header:
10
10
  Authorization: Bearer YOUR_ACCESS_TOKEN
11
11
  ```
12
12
 
13
- Get your access token from the <a href="https://my.lunchmoney.app/developers" target="_blank" rel="noopener noreferrer">Lunch Money developers page</a>. See the [Getting Started guide](/v2/getting-started) for a step-by-step walkthrough including how to create a test budget.
13
+ Get your access token from the <a href="https://my.lunchmoney.app/developers" target="_blank" rel="noopener noreferrer">Lunch Money Developers page</a>. See the [Getting started guide](/getting-started) for a step-by-step walkthrough including how to create a test budget.
14
14
 
15
15
  ## Base URL
16
16
 
@@ -18,7 +18,7 @@ Get your access token from the <a href="https://my.lunchmoney.app/developers" ta
18
18
  https://api.lunchmoney.dev/v2
19
19
  ```
20
20
 
21
- ## Response Shapes
21
+ ## Response shapes
22
22
 
23
23
  The v2 API uses consistent HTTP status codes and response bodies across all endpoints.
24
24
 
@@ -39,7 +39,7 @@ All errors return an appropriate 4XX status code — the v2 API never returns an
39
39
  | `401` | Unauthorized — missing or invalid Bearer token |
40
40
  | `404` | Not Found — the requested object does not exist |
41
41
  | `422` | Unprocessable Content — request is valid but cannot be fulfilled (e.g., deleting a category with dependents) |
42
- | `429` | Too Many Requests — rate limit exceeded; response includes a `Retry-After` header. See the [Rate Limiting guide](/v2/rate-limits). |
42
+ | `429` | Too Many Requests — rate limit exceeded; response includes a `Retry-After` header. See the [Rate limiting guide](/rate-limits). |
43
43
 
44
44
  All error responses share a consistent body format:
45
45
 
@@ -52,7 +52,7 @@ All error responses share a consistent body format:
52
52
  }
53
53
  ```
54
54
 
55
- > [!NOTE] Atomic Operations
55
+ > [!NOTE] Atomic operations
56
56
  > When a request fails, no part of it is applied to your data. For example, if one transaction in a bulk insert has a validation error, none of the transactions in that request are inserted. Fix the errors and retry — you don't need to worry about partial duplicates.
57
57
  >
58
58
  > If a request has multiple validation errors, the response will attempt to list as many as possible, but it is not guaranteed to catch all errors in a single response.
@@ -61,7 +61,7 @@ All error responses share a consistent body format:
61
61
 
62
62
  The v2 API validates all requests strictly. A `400` is returned if the request includes unexpected parameters, missing required fields, fields with invalid values, or unexpected properties in the request body. This makes it easier to catch mistakes during development.
63
63
 
64
- ## Naming Conventions
64
+ ## Naming conventions
65
65
 
66
66
  Object properties follow consistent rules across the entire API:
67
67
 
@@ -72,11 +72,11 @@ Object properties follow consistent rules across the entire API:
72
72
  - Child objects of the same type are always in a `children` property
73
73
  - All `id` fields are `integer` type (not `number`)
74
74
 
75
- ## Amounts, Balances & Sign Convention
75
+ ## Amounts, balances & sign convention
76
76
 
77
- The v2 API uses a consistent set of properties — `amount`, `balance`, `currency`, and `to_base` — across all objects that deal with money. See the [Amounts & Balances guide](/v2/amounts-and-balances) for a full explanation of how these properties work, including the sign convention and multi-currency support.
77
+ The v2 API uses a consistent set of properties — `amount`, `balance`, `currency`, and `to_base` — across all objects that deal with money. See the [Amounts & balances guide](/amounts-and-balances) for a full explanation of how these properties work, including the sign convention and multi-currency support.
78
78
 
79
- ## Hydrated vs. Non-Hydrated Responses
79
+ ## Hydrated vs. non-hydrated responses
80
80
 
81
81
  In v1, some endpoints returned "hydrated" objects — related object details were embedded directly in the response alongside their IDs. For example, a transaction included `category_name`, `asset_name`, and an array of full tag objects.
82
82
 
@@ -93,17 +93,17 @@ In v2, responses are **non-hydrated**: related objects are returned as IDs only.
93
93
 
94
94
  This improves response times and keeps the API consistent. For apps that need related object details frequently, maintaining a local cache of categories, accounts, and tags is the recommended pattern.
95
95
 
96
- ## Updating Objects (PUT)
96
+ ## Updating objects (PUT)
97
97
 
98
98
  Most objects in the v2 API are updatable via `PUT /endpoint/{id}`. The rules are consistent:
99
99
 
100
100
  - Request bodies may contain any mix of **user-definable** properties (will be updated) and **system-defined** properties like `id` or `created_at` (accepted but ignored).
101
101
  - Any unexpected property that is neither user-definable nor system-defined will fail validation and return `400`.
102
102
 
103
- > [!WARNING] Overwrite Behavior
103
+ > [!WARNING] Overwrite behavior
104
104
  > Complex properties — objects and arrays — are **replaced entirely** by whatever is in the request body. To add a tag to a transaction without removing existing tags, first fetch the transaction, add the new tag ID to the existing `tag_ids` array, then PUT the full updated array.
105
105
 
106
- > [!TIP] Recommended Pattern
106
+ > [!TIP] Recommended pattern
107
107
  > Because system-defined properties are tolerated in PUT requests, you can safely GET an object, modify the properties you want to change, and PUT the whole thing back without stripping system fields first.
108
108
 
109
109
  ## Versioning
@@ -99,7 +99,7 @@ One change worth noting: all `id` fields are now explicitly `integer` type (not
99
99
 
100
100
  #### New Properties
101
101
 
102
- - `debits_as_negative`: A user preference shown in the Lunch Money app. This no longer changes how transaction amounts are represented in the v2 API, but apps may use this setting to display amounts and balances in the way the user prefers. See the [Amounts & Balances guide](/v2/amounts-and-balances) for details.
102
+ - `debits_as_negative`: A user preference shown in the Lunch Money app. This no longer changes how transaction amounts are represented in the v2 API, but apps may use this setting to display amounts and balances in the way the user prefers. See the [Amounts & balances guide](/amounts-and-balances) for details.
103
103
 
104
104
  <a href="./changelog-visual#user-object-row" target="_blank" rel="noopener noreferrer">View v1/v2 differences</a>
105
105
 
@@ -386,7 +386,7 @@ GET /v2/transactions
386
386
  > [!WARNING] Behavior Change
387
387
  > In the v1 API the optional `debit_as_negative` query parameter could change how transaction amounts were represented. In the v2 API, transaction amount signs are fixed: positive values are debits and negative values are credits. Existing applications that assume positive values are credits need to be updated.
388
388
 
389
- See the [Amounts & Balances guide](/v2/amounts-and-balances) for the full sign convention and how `to_base` works for multi-currency accounts.
389
+ See the [Amounts & balances guide](/amounts-and-balances) for the full sign convention and how `to_base` works for multi-currency accounts.
390
390
 
391
391
 
392
392
  > [!TIP] Migration Tip
@@ -5,11 +5,10 @@ The Lunch Money API spec uses a modified version of SEMVER for its versioning me
5
5
  - The minor version represents the number of main endpoints the current version of the spec supports. For example, a version of the API that supports the /me, /categories, and /transactions endpoints would have a minor version of 3.
6
6
  - The revision number represents the number of updates since the last endpoint was added. For example, each time changes are made to one of the existing three APIs as described above, the revision number will be bumped.
7
7
 
8
- ## v2.11.1 - TBD
8
+ ## v2.11.1 - Sep 28, 2026
9
9
  - Add `GET /me/account/settings` and `PUT /me/account/settings` for account-level settings
10
10
  - Add `GET /me/user/settings` and `PUT /me/user/settings` for user-level display and formatting preferences
11
11
  - Add `GET /me/user/account/settings` and `PUT /me/user/account/settings` for settings specific to a user and budgeting account
12
- from `GET /me/account/settings` and `PUT /me/account/settings` to `GET /me/user/account/settings` and `PUT /me/user/account/settings`
13
12
  - Add `include_pending_in_totals` to `GET /me/account/settings` and `PUT /me/account/settings`
14
13
  - Add `default_manual_account_id` to `GET /me/user/account/settings` and `PUT /me/user/account/settings`
15
14
  - Document `GET /budgets/settings` response schema publicly; change `budget_period_quantity` to integer