mibudge

mibudge API

REST API for the mibudge personal budgeting service.

Authentication

All endpoints require JWT authentication via Authorization: Bearer <token> header. Obtain tokens through the login flow; refresh via POST /api/token/refresh/ (httpOnly cookie).

Permissions

Money fields

Monetary values are represented as a decimal amount paired with an ISO 4217 currency code (e.g. amount + amount_currency). Currency defaults to the account’s currency if not specified.

Version: 1.0.0

Authentication

Endpoints

api

POST /api/token/

Operation: api_token_create

JWT obtain endpoint that stores the refresh token in an httpOnly cookie and returns only the access token in the response body.

This is the browser-SPA login flow: JS receives the short-lived access token (kept in memory); the refresh token is a Secure/HttpOnly/SameSite=Strict cookie that JS cannot read, and that the browser sends automatically to /api/token/refresh/.

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 200: No response body

POST /api/token/refresh/

Operation: api_token_refresh_create

JWT refresh endpoint that reads the refresh token from the httpOnly cookie rather than the request body.

On success, returns {“access”: “"} in JSON. When token rotation is enabled, also rotates the refresh cookie so the 14-day sliding window resets with each use.

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 200:

allocations

GET /api/v1/allocations/

Operation: allocations_list

Return allocations belonging to the authenticated user’s transactions. Filterable by transaction, budget, and category. Orderable by created_at.

Parameters:

Response 200:

GET /api/v1/allocations/{id}/

Operation: allocations_retrieve

Return a single transaction allocation by UUID.

Parameters:

Response 200:

bank-accounts

GET /api/v1/bank-accounts/

Operation: bank_accounts_list

Return bank accounts owned by the authenticated user. Filterable by account_type. Orderable by name or created_at.

Parameters:

Response 200:

POST /api/v1/bank-accounts/

Operation: bank_accounts_create

Create a new bank account. The authenticated user is automatically added as an owner. An ‘Unallocated’ budget is auto-created by a post_save signal. Optionally set initial posted_balance, available_balance, and currency (all immutable after creation).

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 201:

GET /api/v1/bank-accounts/{id}/

Operation: bank_accounts_retrieve

Return a single bank account by UUID.

Parameters:

Response 200:

PUT /api/v1/bank-accounts/{id}/

Operation: bank_accounts_update

Full update of a bank account. Only ‘name’ is mutable after creation – bank, account_type, currency, and balances are rejected if changed.

Parameters:

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 200:

PATCH /api/v1/bank-accounts/{id}/

Operation: bank_accounts_partial_update

Partial update of a bank account. Only ‘name’ is mutable after creation.

Parameters:

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 200:

DELETE /api/v1/bank-accounts/{id}/

Operation: bank_accounts_destroy

Delete a bank account and all associated budgets, transactions, and allocations.

Parameters:

Response 204: No response body

GET /api/v1/bank-accounts/{id}/funding-event-dates/

Operation: bank_accounts_funding_event_dates_retrieve

Return all dates in (after, before] on which at least one funding or recurrence event is due for this account. The importer uses this to find batch-split boundaries.

Parameters:

Response 200: Sorted list of event dates.

GET /api/v1/bank-accounts/{id}/funding-summary/

Operation: bank_accounts_funding_summary_retrieve

Return the total amounts that will be automatically funded at the next event for each distinct funding schedule on this account. Only active, schedulable budgets are included – paused, archived, completed goals, and RECURRING budgets that delegate to a fill-up goal are excluded. Results are grouped by funding schedule (RRULE string) and sorted by next event date.

Parameters:

Response 200: Per-schedule funding totals.

POST /api/v1/bank-accounts/{id}/mark-imported/

Operation: bank_accounts_mark_imported_create

Record that a transaction import has been completed for this account. Sets last_imported_at to now and advances last_posted_through to the supplied date (never regresses an existing value). Body: {“last_posted_through”: “YYYY-MM-DD”}.

Parameters:

Request Body (application/json):

Response 200:

POST /api/v1/bank-accounts/{id}/run-funding/

Operation: bank_accounts_run_funding_create

Run the funding engine for this account immediately. Processes all due fund and recurrence events up to as_of (defaults to today) and returns a summary of what happened. Pass as_of when calling between import batches so the engine only sees events up to that batch boundary date.

Parameters:

Request Body (application/json):

Response 200: Funding run result.

Response 409: Either another worker is currently processing this account (lock held), or there is nothing due or outstanding to run as of the supplied date.

POST /api/v1/bank-accounts/{id}/sync-scrape/

Operation: bank_accounts_sync_scrape_create

Reconcile this account against a fresh snapshot from a live bank scraper. All existing pending transactions on the account are deleted, posted transactions from the scrape are de-duplicated against the database, and any new posted/pending rows are inserted in the order the scraper supplies (newest-first). Per-transaction running balance snapshots and the unallocated-budget allocation snapshots are recomputed before the request returns. Runs atomically under the account + unallocated-budget locks; on any error the database is unchanged.

Parameters:

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 200:

banks

GET /api/v1/banks/

Operation: banks_list

Return all banks in the system. Banks are shared reference data managed through the admin – any authenticated user can list and retrieve them.

Parameters:

Response 200:

GET /api/v1/banks/{id}/

Operation: banks_retrieve

Return a single bank by UUID.

Parameters:

Response 200:

budgets

GET /api/v1/budgets/

Operation: budgets_list

Return budgets belonging to the authenticated user’s accounts. Filterable by bank_account, budget_type, archived, and paused. Searchable by name. Orderable by name, created_at, or balance.

Parameters:

Response 200:

POST /api/v1/budgets/

Operation: budgets_create

Create a new budget under a bank account. Required: name, bank_account (UUID), budget_type, funding_type, and target_balance. The bank_account and budget_type are immutable after creation. Balance is managed by signals and is always read-only.

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 201:

Args: obj: The Budget instance being serialized.

Returns: Dict with ‘date’, ‘amount’, ‘amount_currency’, or None.

GET /api/v1/budgets/{id}/

Operation: budgets_retrieve

Return a single budget by UUID.

Parameters:

Response 200:

Args: obj: The Budget instance being serialized.

Returns: Dict with ‘date’, ‘amount’, ‘amount_currency’, or None.

PUT /api/v1/budgets/{id}/

Operation: budgets_update

Full update of a budget. bank_account and budget_type are immutable. The unallocated budget cannot be renamed.

Parameters:

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 200:

Args: obj: The Budget instance being serialized.

Returns: Dict with ‘date’, ‘amount’, ‘amount_currency’, or None.

PATCH /api/v1/budgets/{id}/

Operation: budgets_partial_update

Partial update of a budget. bank_account and budget_type are immutable. The unallocated budget cannot be renamed.

Parameters:

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 200:

Args: obj: The Budget instance being serialized.

Returns: Dict with ‘date’, ‘amount’, ‘amount_currency’, or None.

DELETE /api/v1/budgets/{id}/

Operation: budgets_destroy

Delete a budget. The unallocated budget cannot be deleted (403). A budget with existing transaction allocations cannot be deleted (400) – archive it instead.

Parameters:

Response 204: No response body

POST /api/v1/budgets/{id}/archive/

Operation: budgets_archive_create

Archive a budget. Any remaining balance is transferred to the account’s unallocated budget. If the budget has an associated fill-up goal, that budget is also archived and its balance moved to unallocated. The unallocated budget cannot be archived.

Parameters:

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 200:

Args: obj: The Budget instance being serialized.

Returns: Dict with ‘date’, ‘amount’, ‘amount_currency’, or None.

channel-preferences

GET /api/v1/channel-preferences/

Operation: channel_preferences_list

Return all notification channels with the authenticated user’s delivery preferences. Channels without a stored preference fall back to DAILY_MORNING.

Parameters:

Response 200:

PATCH /api/v1/channel-preferences/{channel}/

Operation: channel_preferences_partial_update

Set the digest_frequency for a notification channel. Returns 404 if the channel value is not valid.

Parameters:

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 200:

currencies

GET /api/v1/currencies/

Operation: currencies_retrieve

Return all ISO 4217 currency codes supported by the system, sorted by code. Each entry includes the code, English name, and numeric ISO 4217 code. Requires authentication.

Response 200: List of supported currencies.

funding-occurrences

GET /api/v1/funding-occurrences/

Operation: funding_occurrences_list

Return funding event occurrences for budgets on accounts owned by the authenticated user. Filterable by bank_account, budget, kind, status (multi-value), and scheduled_date range. Orderable by scheduled_date or created_at.

Parameters:

Response 200:

GET /api/v1/funding-occurrences/{id}/

Operation: funding_occurrences_retrieve

Return a single funding event occurrence by UUID.

Parameters:

Response 200:

internal-transactions

GET /api/v1/internal-transactions/

Operation: internal_transactions_list

Return budget-to-budget transfers belonging to the authenticated user’s accounts. Filterable by bank_account, src_budget, dst_budget, and date range (date_from/date_to). Orderable by created_at.

Parameters:

Response 200:

POST /api/v1/internal-transactions/

Operation: internal_transactions_create

Transfer money between two budgets in the same bank account. Required: bank_account (UUID), amount, src_budget (UUID), and dst_budget (UUID). The authenticated user is recorded as the actor. Internal transactions are write-once – to reverse a transfer, create a new one with src and dst swapped.

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 201:

GET /api/v1/internal-transactions/{id}/

Operation: internal_transactions_retrieve

Return a single internal transaction by UUID.

Parameters:

Response 200:

notification-preferences

GET /api/v1/notification-preferences/

Operation: notification_preferences_list

Return all registered notification kinds merged with the authenticated user’s preferences. Kinds without a stored preference fall back to the registry default_delivery_mode.

Parameters:

Response 200:

PATCH /api/v1/notification-preferences/{kind}/

Operation: notification_preferences_partial_update

Set delivery_mode (‘digest’, ‘immediate’, or ‘off’) for a single notification kind. Returns 400 if the kind has can_suppress=False. Returns 404 if the kind is not registered.

Parameters:

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 200:

transactions

GET /api/v1/transactions/

Operation: transactions_list

Return transactions belonging to the authenticated user’s accounts. Filterable by bank_account, pending status, transaction_type, and date range (date_from/date_to). Searchable by description, raw_description, and party. Orderable by transaction_date, amount, or created_at.

Parameters:

Response 200:

POST /api/v1/transactions/

Operation: transactions_create

Create a new bank transaction. Required: bank_account (UUID), amount, transaction_date, transaction_type, and raw_description. A default TransactionAllocation to the bank account’s unallocated budget is auto-created. After creation, only transaction_type, memo, and description are updatable.

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 201:

GET /api/v1/transactions/{id}/

Operation: transactions_retrieve

Return a single transaction by UUID.

Parameters:

Response 200:

PUT /api/v1/transactions/{id}/

Operation: transactions_update

Full update of a transaction. Only transaction_type, memo, and description are mutable after creation.

Parameters:

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 200:

PATCH /api/v1/transactions/{id}/

Operation: transactions_partial_update

Partial update of a transaction. Only transaction_type, memo, and description are mutable after creation.

Parameters:

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 200:

DELETE /api/v1/transactions/{id}/

Operation: transactions_destroy

Delete a transaction. Balance changes are reversed by the pre_delete signal. Associated allocations are cascade-deleted.

Parameters:

Response 204: No response body

POST /api/v1/transactions/{id}/resolve-pending/

Operation: transactions_resolve_pending_create

Transition a pending transaction to posted status. Supplies the bank-confirmed posted date and optionally a final settled amount (which may differ from the pending estimate). The bank account’s posted_balance is credited; if the amount changed, available_balance and the Unallocated allocation are adjusted atomically.

Parameters:

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 200:

POST /api/v1/transactions/{id}/splits/

Operation: transactions_splits_create

Declaratively set how a transaction’s amount is split across budgets. All referenced budgets must belong to the same bank account as the transaction. The backend reconciles existing allocations to match: creating, updating, or deleting as needed. Any unallocated remainder gets an allocation to the account’s unallocated budget. Returns all allocations for this transaction after reconciliation.

Parameters:

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 200:

users

GET /api/v1/users/

Operation: users_list

Return all users. Restricted to staff/admin users.

Parameters:

Response 200:

GET /api/v1/users/{username}/

Operation: users_retrieve

Return a single user by username. Restricted to staff/admin users.

Parameters:

Response 200:

PUT /api/v1/users/{username}/

Operation: users_update

Full update of a user profile. Restricted to staff/admin users.

Parameters:

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 200:

PATCH /api/v1/users/{username}/

Operation: users_partial_update

Partial update of a user profile. Restricted to staff/admin users.

Parameters:

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 200:

GET /api/v1/users/me/

Operation: users_me_retrieve

GET returns the authenticated user’s own profile. PATCH allows updating the name field. Available to any authenticated user (not restricted to staff).

Response 200:

PATCH /api/v1/users/me/

Operation: users_me_partial_update

GET returns the authenticated user’s own profile. PATCH allows updating the name field. Available to any authenticated user (not restricted to staff).

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 200:

POST /api/v1/users/me/change-password/

Operation: users_me_change_password_create

Change the authenticated user’s password. Requires the current password for verification. The new password must score at least 2 on the zxcvbn scale. Existing JWT tokens remain valid; the caller may silently refresh as normal – no forced re-login is imposed.

Request Body (application/json):

Request Body (application/x-www-form-urlencoded):

Request Body (multipart/form-data):

Response 204: No response body

Schemas

AccountTypeEnum

Bank

Read-only serializer for banks.

Banks are shared reference data managed only through the admin.

BankAccount

Serializer for bank accounts.

On create the caller supplies name, bank (UUID), account_type, account_number, and optionally currency and initial balances. The view routes creation through BankAccountService which adds the requesting user as owner and seeds the Unallocated budget.

After creation, name and account_number are updatable. Currency, account_type, bank, and balances are immutable once the account exists.

Group assignment is not yet supported via the API.

BankAccountRequest

Serializer for bank accounts.

On create the caller supplies name, bank (UUID), account_type, account_number, and optionally currency and initial balances. The view routes creation through BankAccountService which adds the requesting user as owner and seeds the Unallocated budget.

After creation, name and account_number are updatable. Currency, account_type, bank, and balances are immutable once the account exists.

Group assignment is not yet supported via the API.

BlankEnum

Budget

Serializer for budgets.

On create the caller supplies bank_account (UUID) and budget properties. After creation, bank_account and budget_type are immutable. Balance is managed by signals and is always read-only. The unallocated budget’s name cannot be changed.

Currency is inherited from the bank account via the pre_save signal and is not accepted from the client.

Args: obj: The Budget instance being serialized.

Returns: Dict with ‘date’, ‘amount’, ‘amount_currency’, or None.

BudgetRequest

Serializer for budgets.

On create the caller supplies bank_account (UUID) and budget properties. After creation, bank_account and budget_type are immutable. Balance is managed by signals and is always read-only. The unallocated budget’s name cannot be changed.

Currency is inherited from the bank account via the pre_save signal and is not accepted from the client.

BudgetTypeEnum

CategoryEnum

ChangePasswordRequest

Validate a password-change request.

Checks that the new password is strong enough (zxcvbn score >= 2) and that the two new-password fields match. Current-password verification and the actual password update are handled in the view.

ChannelPreference

Channel delivery preference.

Read: channel, display_name, digest_frequency. Write (PATCH): digest_frequency only.

DeliveryModeEnum

DigestFrequencyEnum

EmailTokenObtainPairRequest

TokenObtainPairSerializer variant that uses email as the login field instead of username.

USERNAME_FIELD is kept as “username” so Django admin is unaffected; we override username_field here so simplejwt presents an email field in the login payload and passes it to EmailBackend.authenticate().

FundingEventOccurrence

Read-only serializer for FundingEventOccurrence rows.

Exposes the budget UUID as ‘budget’ rather than the internal pkid so callers can cross-reference with the Budget endpoint.

FundingTypeEnum

InternalTransaction

Serializer for internal transactions (budget-to-budget transfers).

Internal transactions are write-once: the API supports create and read but not update or delete. To reverse a transfer, create a new internal transaction with the src and dst budgets swapped.

On create the caller supplies bank_account, amount, src_budget, and dst_budget. The view sets the actor to the requesting user.

The amount_currency is read from raw request data by djmoney’s MoneyField.get_value() – no explicit currency field declaration is needed.

InternalTransactionRequest

Serializer for internal transactions (budget-to-budget transfers).

Internal transactions are write-once: the API supports create and read but not update or delete. To reverse a transfer, create a new internal transaction with the src and dst budgets swapped.

On create the caller supplies bank_account, amount, src_budget, and dst_budget. The view sets the actor to the requesting user.

The amount_currency is read from raw request data by djmoney’s MoneyField.get_value() – no explicit currency field declaration is needed.

NotificationPreference

Notification kind preference.

Read: kind, display_name, can_suppress, delivery_mode. Write (PATCH): delivery_mode only (rejected for can_suppress=False kinds).

PaginatedBankAccountList

PaginatedBankList

PaginatedBudgetList

PaginatedChannelPreferenceList

PaginatedFundingEventOccurrenceList

PaginatedInternalTransactionList

PaginatedNotificationPreferenceList

PaginatedTransactionAllocationList

PaginatedTransactionList

PaginatedUserList

PatchedBankAccountRequest

Serializer for bank accounts.

On create the caller supplies name, bank (UUID), account_type, account_number, and optionally currency and initial balances. The view routes creation through BankAccountService which adds the requesting user as owner and seeds the Unallocated budget.

After creation, name and account_number are updatable. Currency, account_type, bank, and balances are immutable once the account exists.

Group assignment is not yet supported via the API.

PatchedBudgetRequest

Serializer for budgets.

On create the caller supplies bank_account (UUID) and budget properties. After creation, bank_account and budget_type are immutable. Balance is managed by signals and is always read-only. The unallocated budget’s name cannot be changed.

Currency is inherited from the bank account via the pre_save signal and is not accepted from the client.

PatchedChannelPreferenceRequest

Channel delivery preference.

Read: channel, display_name, digest_frequency. Write (PATCH): digest_frequency only.

PatchedNotificationPreferenceRequest

Notification kind preference.

Read: kind, display_name, can_suppress, delivery_mode. Write (PATCH): delivery_mode only (rejected for can_suppress=False kinds).

PatchedTransactionRequest

Serializer for bank transactions.

On create the caller supplies bank_account, amount, transaction_date, transaction_type, raw_description, and optionally pending, memo, and description.

After creation only transaction_type, memo, and description are updatable. The view is responsible for creating the default TransactionAllocation to the unallocated budget on create.

The amount_currency is read from raw request data by djmoney’s MoneyField.get_value() – no explicit currency field declaration is needed.

PatchedUserRequest

Serializer for user profiles.

The default_bank_account field is writable but constrained: the bank account must be owned by the user being updated. On output it returns the UUID string (or null).

ResolvePendingRequest

Input serializer for the resolve-pending action.

Validates the settled posted_date and optional final amount. Requires transaction in the serializer context for sign validation.

ScrapeSyncReport

Output serializer for the bank-account scrape-sync action.

Mirrors service.sync_scrape.ScrapeSyncReport. Reports everything the caller needs to summarise what changed and surface validation warnings.

ScrapeSyncRequest

Input serializer for the bank-account scrape-sync action.

Validates a full bank-side snapshot for one account: when the scrape was taken, the bank’s ending available balance, and the list of transactions (newest-first as the bank renders them).

ScrapeSyncTransactionRequest

One transaction in a scrape-sync payload.

Mirrors service.sync_scrape.ScrapedTransaction. Pending rows carry the scrape’s local posted_date (banks typically render pending rows without a real settlement date – e.g. BofA shows ‘Processing’ in the date column – and the scraper substitutes the current local datetime). Posted rows carry the bank-supplied settlement datetime. transaction_date is derived server-side from the embedded MM/DD pattern in raw_description.

running_balance is optional and used only for the posting-order sanity walk; never persisted.

StatusEnum

TokenRefresh

TokenRefreshRequest

Transaction

Serializer for bank transactions.

On create the caller supplies bank_account, amount, transaction_date, transaction_type, raw_description, and optionally pending, memo, and description.

After creation only transaction_type, memo, and description are updatable. The view is responsible for creating the default TransactionAllocation to the unallocated budget on create.

The amount_currency is read from raw request data by djmoney’s MoneyField.get_value() – no explicit currency field declaration is needed.

TransactionAllocation

Serializer for transaction allocations.

An allocation maps a portion of a transaction’s amount to a budget. On create the caller supplies transaction, amount, and optionally budget (defaults to unallocated) and category. After creation, budget, category, and memo are updatable.

The serializer enforces two key constraints:

  1. Same-account restriction – the budget must belong to the same bank account as the transaction. Cross-account allocations are rejected with a 400 error.
  2. Sum constraint – the total allocated amount across all allocations for a transaction must not exceed the transaction amount.

The amount_currency is read from raw request data by djmoney’s MoneyField.get_value() – no explicit currency field declaration is needed.

TransactionRequest

Serializer for bank transactions.

On create the caller supplies bank_account, amount, transaction_date, transaction_type, raw_description, and optionally pending, memo, and description.

After creation only transaction_type, memo, and description are updatable. The view is responsible for creating the default TransactionAllocation to the unallocated budget on create.

The amount_currency is read from raw request data by djmoney’s MoneyField.get_value() – no explicit currency field declaration is needed.

TransactionSplitsRequest

Serializer for the declarative splits endpoint.

Accepts a dict mapping budget UUIDs to amounts. The backend reconciles existing allocations to match the declared state. Any remainder goes to the unallocated budget.

All budgets must belong to the same bank account as the transaction. Cross-account budget references are rejected with a 400 error.

TransactionTypeEnum

User

Serializer for user profiles.

The default_bank_account field is writable but constrained: the bank account must be owned by the user being updated. On output it returns the UUID string (or null).

UserRequest

Serializer for user profiles.

The default_bank_account field is writable but constrained: the bank account must be owned by the user being updated. On output it returns the UUID string (or null).