[PR #6746] [MERGED] Add Tag API #32633

Closed
opened 2026-04-18 08:38:38 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/actualbudget/actual/pull/6746
Author: @pouwerkerk
Created: 1/22/2026
Status: Merged
Merged: 2/10/2026
Merged by: @MatissJanis

Base: masterHead: add-tags-api


📝 Commits (8)

  • 7703f91 Add Tag API
  • 4d21a49 Add Tag API tests
  • 1491c94 Add Release Note for #6746
  • b8676c9 Make release note more user-facing
  • 18461dd Remove unnecessary type coercion in tagModel.fromExternal
  • 8d9dd00 Merge branch 'master' into add-tags-api
  • ca54b45 Merge branch 'master' into add-tags-api
  • 85d7762 Merge branch 'master' into add-tags-api

📊 Changes

7 files changed (+229 additions, -2 deletions)

View changed files

📝 packages/api/methods.test.ts (+137 -0)
📝 packages/api/methods.ts (+20 -0)
📝 packages/loot-core/src/server/api-models.ts (+21 -0)
📝 packages/loot-core/src/server/api.ts (+27 -0)
📝 packages/loot-core/src/server/tags/app.ts (+4 -2)
📝 packages/loot-core/src/types/api-handlers.ts (+14 -0)
upcoming-release-notes/6746.md (+6 -0)

📄 Description

Summary

Add public API methods for tag management (getTags, createTag, updateTag, deleteTag), enabling external integrations and scripts to work with tags programmatically.

Motivation

Tags were recently added to Actual but lack public API exposure. I had realized this when I was trying to build a client for organizing my budget programmatically but generally this prevents users from managing tags via automation, imports, or custom integrations. This PR follows the established patterns used by the existing payee and category APIs.

Changes

New API methods:

  • getTags() - retrieve all tags
  • createTag(tag) - create a tag with name, optional color and description
  • updateTag(id, fields) - update tag fields (partial updates supported)
  • deleteTag(id) - delete a tag by ID

Internal type improvements:

  • deleteTag handler now accepts Pick<TagEntity, 'id'> instead of requiring a full entity
  • updateTag handler accepts Partial<TagEntity> & Pick<TagEntity, 'id'> to properly support partial updates

These type fixes eliminate unnecessary workarounds in the API layer (e.g., passing empty strings for unused required fields).

Test plan

  • yarn typecheck passes
  • yarn lint passes
  • yarn workspace @actual-app/api test passes (16 tests)

Test coverage includes:

  • Basic CRUD operations
  • Minimal tag creation (name only)
  • Partial updates (verifying unchanged fields are preserved)
  • Null value handling
  • Clearing optional fields by setting to null
yarn workspace @actual-app/api test
✓ built in 1.88s

RUN v4.0.17 /Users/pieter/Documents/actual/packages/api

✓ methods.test.ts (16 tests) 1053ms
✓ API setup and teardown (1)
✓ successfully loads budget 68ms
✓ API CRUD operations (14)
✓ getBudgets 56ms
✓ CategoryGroups: successfully update category groups 89ms
✓ Categories: successfully update categories 70ms
✓ Budgets: successfully update budgets 86ms
✓ Accounts: successfully complete account operators 67ms
✓ Payees: successfully update payees 59ms
✓ Tags: successfully complete tag operations 63ms
✓ Tags: create tag with minimal fields 47ms
✓ Tags: update single field only 60ms
✓ Tags: handle null values correctly 62ms
✓ Tags: clear optional field 56ms
✓ Rules: successfully update rules 55ms
✓ Transactions: successfully update transactions 74ms
✓ Transactions: import notes are preserved when importing 59ms
✓ Schedules: successfully complete schedules operations 81ms

Test Files 1 passed (1)
Tests 16 passed (16)
Start at 16:06:39
Duration 2.32s (transform 1.05s, setup 0ms, import 1.21s, tests 1.05s, environment 0ms)


Bundle Stats

Bundle Files count Total bundle size % Changed
desktop-client 27 14.48 MB 0%
loot-core 1 5.86 MB → 5.86 MB (+1.03 kB) +0.02%
api 1 4.39 MB → 4.39 MB (+918 B) +0.02%
View detailed bundle stats

desktop-client

Total

Files count Total bundle size % Changed
27 14.48 MB 0%
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger
No assets were bigger

Smaller
No assets were smaller

Unchanged

Asset File Size % Changed
static/js/index.js 9.33 MB 0%
static/js/indexeddb-main-thread-worker-e59fee74.js 12.94 kB 0%
static/js/workbox-window.prod.es5.js 5.64 kB 0%
static/js/da.js 106.62 kB 0%
static/js/de.js 178.39 kB 0%
static/js/en-GB.js 7.18 kB 0%
static/js/en.js 164.55 kB 0%
static/js/es.js 173.83 kB 0%
static/js/fr.js 179.62 kB 0%
static/js/it.js 171.44 kB 0%
static/js/nb-NO.js 157.23 kB 0%
static/js/nl.js 106.65 kB 0%
static/js/pl.js 88.64 kB 0%
static/js/pt-BR.js 154.57 kB 0%
static/js/sv.js 78.2 kB 0%
static/js/th.js 182.35 kB 0%
static/js/uk.js 215.11 kB 0%
static/js/resize-observer.js 18.37 kB 0%
static/js/BackgroundImage.js 120.54 kB 0%
static/js/ReportRouter.js 1.12 MB 0%
static/js/narrow.js 640.46 kB 0%
static/js/TransactionList.js 105.97 kB 0%
static/js/wide.js 160.07 kB 0%
static/js/AppliedFilters.js 9.71 kB 0%
static/js/usePayeeRuleCounts.js 11.79 kB 0%
static/js/useTransactionBatchActions.js 13.23 kB 0%
static/js/FormulaEditor.js 1.04 MB 0%

loot-core

Total

Files count Total bundle size % Changed
1 5.86 MB → 5.86 MB (+1.03 kB) +0.02%
Changeset
File Δ Size
home/runner/work/actual/actual/packages/loot-core/src/server/api-models.ts 📈 +274 B (+6.39%) 4.19 kB → 4.46 kB
home/runner/work/actual/actual/packages/loot-core/src/server/api.ts 📈 +784 B (+3.04%) 25.17 kB → 25.94 kB
View detailed bundle breakdown

Added

Asset File Size % Changed
kcab.worker.BmGAOUic.js 0 B → 5.86 MB (+5.86 MB) -

Removed

Asset File Size % Changed
kcab.worker.G2jIa5TY.js 5.86 MB → 0 B (-5.86 MB) -100%

Bigger
No assets were bigger

Smaller
No assets were smaller

Unchanged
No assets were unchanged


api

Total

Files count Total bundle size % Changed
1 4.39 MB → 4.39 MB (+918 B) +0.02%
Changeset
File Δ Size
src/server/api-models.ts 📈 +222 B (+6.00%) 3.62 kB → 3.83 kB
src/server/api.ts 📈 +696 B (+3.09%) 22.02 kB → 22.7 kB
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger

Asset File Size % Changed
bundle.api.js 4.39 MB → 4.39 MB (+918 B) +0.02%

Smaller
No assets were smaller

Unchanged
No assets were unchanged


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/actualbudget/actual/pull/6746 **Author:** [@pouwerkerk](https://github.com/pouwerkerk) **Created:** 1/22/2026 **Status:** ✅ Merged **Merged:** 2/10/2026 **Merged by:** [@MatissJanis](https://github.com/MatissJanis) **Base:** `master` ← **Head:** `add-tags-api` --- ### 📝 Commits (8) - [`7703f91`](https://github.com/actualbudget/actual/commit/7703f91c85b139e2c6174aad7475c4bd6087c208) Add Tag API - [`4d21a49`](https://github.com/actualbudget/actual/commit/4d21a4999d869b1fef407877321f5b538a5b819a) Add Tag API tests - [`1491c94`](https://github.com/actualbudget/actual/commit/1491c940e5f8ead820532d9aa588ff2b3150c7da) Add Release Note for #6746 - [`b8676c9`](https://github.com/actualbudget/actual/commit/b8676c9317048b2f4086b4e1b06cda8ca7c354c2) Make release note more user-facing - [`18461dd`](https://github.com/actualbudget/actual/commit/18461dd5ded57762c828277f6383a6483a8595e8) Remove unnecessary type coercion in tagModel.fromExternal - [`8d9dd00`](https://github.com/actualbudget/actual/commit/8d9dd0077c3936eefc1997693406ca9045be31b6) Merge branch 'master' into add-tags-api - [`ca54b45`](https://github.com/actualbudget/actual/commit/ca54b45d735f9d7db7e6b9b696c6ed021047bf83) Merge branch 'master' into add-tags-api - [`85d7762`](https://github.com/actualbudget/actual/commit/85d7762e2b6e84bc262b3aeb8e119c257d1bc12a) Merge branch 'master' into add-tags-api ### 📊 Changes **7 files changed** (+229 additions, -2 deletions) <details> <summary>View changed files</summary> 📝 `packages/api/methods.test.ts` (+137 -0) 📝 `packages/api/methods.ts` (+20 -0) 📝 `packages/loot-core/src/server/api-models.ts` (+21 -0) 📝 `packages/loot-core/src/server/api.ts` (+27 -0) 📝 `packages/loot-core/src/server/tags/app.ts` (+4 -2) 📝 `packages/loot-core/src/types/api-handlers.ts` (+14 -0) ➕ `upcoming-release-notes/6746.md` (+6 -0) </details> ### 📄 Description ## Summary Add public API methods for tag management (`getTags`, `createTag`, `updateTag`, `deleteTag`), enabling external integrations and scripts to work with tags programmatically. ## Motivation Tags were [recently added to Actual](https://github.com/actualbudget/actual/pull/5032) but lack public API exposure. I had realized this when I was trying to build a client for organizing my budget programmatically but generally this prevents users from managing tags via automation, imports, or custom integrations. This PR follows the established patterns used by the existing payee and category APIs. ## Changes **New API methods:** - `getTags()` - retrieve all tags - `createTag(tag)` - create a tag with name, optional color and description - `updateTag(id, fields)` - update tag fields (partial updates supported) - `deleteTag(id)` - delete a tag by ID **Internal type improvements:** - `deleteTag` handler now accepts `Pick<TagEntity, 'id'>` instead of requiring a full entity - `updateTag` handler accepts `Partial<TagEntity> & Pick<TagEntity, 'id'>` to properly support partial updates These type fixes eliminate unnecessary workarounds in the API layer (e.g., passing empty strings for unused required fields). ## Test plan - [x] `yarn typecheck` passes - [x] `yarn lint` passes - [x] `yarn workspace @actual-app/api test` passes (16 tests) Test coverage includes: - Basic CRUD operations - Minimal tag creation (name only) - Partial updates (verifying unchanged fields are preserved) - Null value handling - Clearing optional fields by setting to null <details> <summary><code>yarn workspace @actual-app/api test</code></summary> <pre> ✓ built in 1.88s RUN v4.0.17 /Users/pieter/Documents/actual/packages/api ✓ methods.test.ts (16 tests) 1053ms ✓ API setup and teardown (1) ✓ successfully loads budget 68ms ✓ API CRUD operations (14) ✓ getBudgets 56ms ✓ CategoryGroups: successfully update category groups 89ms ✓ Categories: successfully update categories 70ms ✓ Budgets: successfully update budgets 86ms ✓ Accounts: successfully complete account operators 67ms ✓ Payees: successfully update payees 59ms ✓ Tags: successfully complete tag operations 63ms ✓ Tags: create tag with minimal fields 47ms ✓ Tags: update single field only 60ms ✓ Tags: handle null values correctly 62ms ✓ Tags: clear optional field 56ms ✓ Rules: successfully update rules 55ms ✓ Transactions: successfully update transactions 74ms ✓ Transactions: import notes are preserved when importing 59ms ✓ Schedules: successfully complete schedules operations 81ms Test Files 1 passed (1) Tests 16 passed (16) Start at 16:06:39 Duration 2.32s (transform 1.05s, setup 0ms, import 1.21s, tests 1.05s, environment 0ms) </pre> </details> <!--- actual-bot-sections ---> <hr /> <!--- bundlestats-action-comment key:combined start ---> ### Bundle Stats Bundle | Files count | Total bundle size | % Changed ------ | ----------- | ----------------- | --------- desktop-client | 27 | 14.48 MB | 0% loot-core | 1 | 5.86 MB → 5.86 MB (+1.03 kB) | +0.02% api | 1 | 4.39 MB → 4.39 MB (+918 B) | +0.02% <details> <summary>View detailed bundle stats</summary> #### desktop-client **Total** Files count | Total bundle size | % Changed ----------- | ----------------- | --------- 27 | 14.48 MB | 0% <details> <summary>View detailed bundle breakdown</summary> <div> **Added** No assets were added **Removed** No assets were removed **Bigger** No assets were bigger **Smaller** No assets were smaller **Unchanged** Asset | File Size | % Changed ----- | --------- | --------- static/js/index.js | 9.33 MB | 0% static/js/indexeddb-main-thread-worker-e59fee74.js | 12.94 kB | 0% static/js/workbox-window.prod.es5.js | 5.64 kB | 0% static/js/da.js | 106.62 kB | 0% static/js/de.js | 178.39 kB | 0% static/js/en-GB.js | 7.18 kB | 0% static/js/en.js | 164.55 kB | 0% static/js/es.js | 173.83 kB | 0% static/js/fr.js | 179.62 kB | 0% static/js/it.js | 171.44 kB | 0% static/js/nb-NO.js | 157.23 kB | 0% static/js/nl.js | 106.65 kB | 0% static/js/pl.js | 88.64 kB | 0% static/js/pt-BR.js | 154.57 kB | 0% static/js/sv.js | 78.2 kB | 0% static/js/th.js | 182.35 kB | 0% static/js/uk.js | 215.11 kB | 0% static/js/resize-observer.js | 18.37 kB | 0% static/js/BackgroundImage.js | 120.54 kB | 0% static/js/ReportRouter.js | 1.12 MB | 0% static/js/narrow.js | 640.46 kB | 0% static/js/TransactionList.js | 105.97 kB | 0% static/js/wide.js | 160.07 kB | 0% static/js/AppliedFilters.js | 9.71 kB | 0% static/js/usePayeeRuleCounts.js | 11.79 kB | 0% static/js/useTransactionBatchActions.js | 13.23 kB | 0% static/js/FormulaEditor.js | 1.04 MB | 0% </div> </details> --- #### loot-core **Total** Files count | Total bundle size | % Changed ----------- | ----------------- | --------- 1 | 5.86 MB → 5.86 MB (+1.03 kB) | +0.02% <details> <summary>Changeset</summary> File | Δ | Size ---- | - | ---- `home/runner/work/actual/actual/packages/loot-core/src/server/api-models.ts` | 📈 +274 B (+6.39%) | 4.19 kB → 4.46 kB `home/runner/work/actual/actual/packages/loot-core/src/server/api.ts` | 📈 +784 B (+3.04%) | 25.17 kB → 25.94 kB </details> <details> <summary>View detailed bundle breakdown</summary> <div> **Added** Asset | File Size | % Changed ----- | --------- | --------- kcab.worker.BmGAOUic.js | 0 B → 5.86 MB (+5.86 MB) | - **Removed** Asset | File Size | % Changed ----- | --------- | --------- kcab.worker.G2jIa5TY.js | 5.86 MB → 0 B (-5.86 MB) | -100% **Bigger** No assets were bigger **Smaller** No assets were smaller **Unchanged** No assets were unchanged </div> </details> --- #### api **Total** Files count | Total bundle size | % Changed ----------- | ----------------- | --------- 1 | 4.39 MB → 4.39 MB (+918 B) | +0.02% <details> <summary>Changeset</summary> File | Δ | Size ---- | - | ---- `src/server/api-models.ts` | 📈 +222 B (+6.00%) | 3.62 kB → 3.83 kB `src/server/api.ts` | 📈 +696 B (+3.09%) | 22.02 kB → 22.7 kB </details> <details> <summary>View detailed bundle breakdown</summary> <div> **Added** No assets were added **Removed** No assets were removed **Bigger** Asset | File Size | % Changed ----- | --------- | --------- bundle.api.js | 4.39 MB → 4.39 MB (+918 B) | +0.02% **Smaller** No assets were smaller **Unchanged** No assets were unchanged </div> </details> </details> <!--- bundlestats-action-comment key:combined end ---> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-04-18 08:38:38 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/actual#32633