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.

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

Operation: bank_accounts_invitations_list

Returns all pending invitations for this bank account.

Parameters:

Response 200:

POST /api/v1/bank-accounts/{id}/invitations/{token}/cancel/

Operation: bank_accounts_invitations_cancel_create

Cancel a pending co-ownership invitation by token. Only the user who sent the invitation may cancel it.

Parameters:

Response 200: No response body

POST /api/v1/bank-accounts/{id}/invite/

Operation: bank_accounts_invite_create

Send a co-ownership invitation to the given email address. If no mibudge account exists for that address, an inactive placeholder account is created; the invitee sets their password after accepting. Returns 409 if the address is already an owner or a pending invitation already exists; 429 if too many invitations have been sent to this address for this account in the rolling window.

Parameters:

Request Body (application/json):

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

Request Body (multipart/form-data):

Response 201: No response body

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:

POST /api/v1/bank-accounts/{id}/transaction-details/

Operation: bank_accounts_transaction_details_create

Apply per-transaction detail records (merchant name, location, MCC, virtual card number) fetched by a live scraper to posted transactions on this account. Each raw details dict is stored verbatim on its transaction and the merchant columns are extracted from it. An item’s optional category is a mibudge category full name (‘{group} : {name}’) – importers translate their provider’s category vocabulary before submitting. It seeds the transaction’s category (and its unassigned allocations) when NULL; an unknown name yields a per-item warning and leaves the transaction unassigned. The display description is recomposed on first enrichment unless the user has edited it. Rows already enriched are skipped unless overwrite is true; pending rows are always skipped. Per-item outcomes are returned in submission order.

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.

The recurrence_schedule’s DTSTART is only the rule’s anchor; this field is the actual upcoming refresh date (first occurrence after last_recurrence_on). Only Recurring budgets have one.

Args: obj: The Budget instance being serialized.

Returns: ISO date string, 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.

The recurrence_schedule’s DTSTART is only the rule’s anchor; this field is the actual upcoming refresh date (first occurrence after last_recurrence_on). Only Recurring budgets have one.

Args: obj: The Budget instance being serialized.

Returns: ISO date string, 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.

The recurrence_schedule’s DTSTART is only the rule’s anchor; this field is the actual upcoming refresh date (first occurrence after last_recurrence_on). Only Recurring budgets have one.

Args: obj: The Budget instance being serialized.

Returns: ISO date string, 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.

The recurrence_schedule’s DTSTART is only the rule’s anchor; this field is the actual upcoming refresh date (first occurrence after last_recurrence_on). Only Recurring budgets have one.

Args: obj: The Budget instance being serialized.

Returns: ISO date string, 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.

The recurrence_schedule’s DTSTART is only the rule’s anchor; this field is the actual upcoming refresh date (first occurrence after last_recurrence_on). Only Recurring budgets have one.

Args: obj: The Budget instance being serialized.

Returns: ISO date string, 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:

invitations

GET /api/v1/invitations/{token}/

Operation: invitations_retrieve

Return bank account name, current owners, and invitee status for the invitation identified by token. No authentication required – the token is the credential. Used by native apps to render the acceptance UI; the Django template view renders this server-side.

Parameters:

Response 200:

POST /api/v1/invitations/{token}/accept/

Operation: invitations_accept_create

Accept the co-ownership invitation identified by token. Adds the invitee to the account’s owners. For brand-new users (no password set), a password-reset email is also dispatched. No authentication required.

Parameters:

Response 200: No response body

Response 400: Invitation expired, cancelled, or already resolved.

Response 404: Invitation not found.

POST /api/v1/invitations/{token}/decline/

Operation: invitations_decline_create

Decline the co-ownership invitation identified by token. No authentication required.

Parameters:

Response 200: No response body

Response 400: Invitation expired, cancelled, or already resolved.

Response 404: Invitation not found.

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:

transaction-categories

GET /api/v1/transaction-categories/

Operation: transaction_categories_list

Return the transaction categories visible to the authenticated user: the global base set, the user’s own custom categories, categories owned by users they co-own a bank account with, and categories still referenced by the user’s transactions after sharing ended. Filterable by group, archived, and scope (global mine shared). Searchable by group and name.

Parameters:

Response 200:

POST /api/v1/transaction-categories/

Operation: transaction_categories_create

Create a custom category owned by the authenticated user (global categories are managed via the admin). Group and name are whitespace-normalized; case-insensitive duplicates of global rows or the user’s own rows are rejected.

Request Body (application/json):

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

Request Body (multipart/form-data):

Response 201:

GET /api/v1/transaction-categories/{id}/

Operation: transaction_categories_retrieve

Return a single visible category by UUID.

Parameters:

Response 200:

PUT /api/v1/transaction-categories/{id}/

Operation: transaction_categories_update

Full update of a category. Only the owner may update; global categories are managed via the admin.

Parameters:

Request Body (application/json):

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

Request Body (multipart/form-data):

Response 200:

PATCH /api/v1/transaction-categories/{id}/

Operation: transaction_categories_partial_update

Partial update of a category. Only the owner may update; global categories are managed via the admin.

Parameters:

Request Body (application/json):

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

Request Body (multipart/form-data):

Response 200:

DELETE /api/v1/transaction-categories/{id}/

Operation: transaction_categories_destroy

Delete a category. Only the owner may delete; global categories are managed via the admin. A category still referenced by transactions or allocations cannot be deleted (409) – archive it instead.

Parameters:

Response 204: No response body

Response 409: The category is referenced by transactions or allocations; archive it instead.

POST /api/v1/transaction-categories/{id}/archive/

Operation: transaction_categories_archive_create

Archive a category so pickers hide it while existing references stay valid. Only the owner may archive; global categories are managed via the admin.

Parameters:

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). GET is also available to machine credentials (API keys) – importers read the timezone field; PATCH requires an interactive login session.

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). GET is also available to machine credentials (API keys) – importers read the timezone field; PATCH requires an interactive login session.

Request Body (application/json):

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

Request Body (multipart/form-data):

Response 200:

GET /api/v1/users/me/api-keys/

Operation: users_me_api_keys_list

Return all API keys (active, expired, and revoked) belonging to the authenticated user. Key material is never included – only the displayable prefix.

Parameters:

Response 200:

POST /api/v1/users/me/api-keys/

Operation: users_me_api_keys_create

Create a new API key for the authenticated user. expiry_days sets the key’s lifetime in days (the UI presets are 30 / 60 / 90 / 365); omit it or pass null for a key that never expires.

The response is the only time the plaintext key is returned; it cannot be recovered afterwards.

Request Body (application/json):

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

Request Body (multipart/form-data):

Response 201:

GET /api/v1/users/me/api-keys/{uuid}/

Operation: users_me_api_keys_retrieve

Return a single API key by its UUID.

Parameters:

Response 200:

POST /api/v1/users/me/api-keys/{uuid}/revoke/

Operation: users_me_api_keys_revoke_create

Permanently revoke an API key. Revoked keys stop authenticating immediately but remain listed for audit purposes. Revocation cannot be undone.

Parameters:

Response 200:

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

Operation: users_me_change_email_create

Initiate a self-service email change. Sends a verification link to the new address and a revocation link to the old address. Returns 403 if the user has no usable password; 409 if new_email is already taken or a revocation window is currently open for this account.

Request Body (application/json):

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

Request Body (multipart/form-data):

Response 201: No response body

POST /api/v1/users/me/change-email/{token}/confirm/

Operation: users_me_change_email_confirm_create

Verify a pending email change using the token from the verification link sent to the new address. No authentication required – the token is the credential.

Dual-path note: The email link points to a Django GET view at /users/email-change/{token}/confirm/ which processes the action and redirects the browser to the SPA result page. Native apps that register mibudge.money as a Universal Link (iOS) or App Link (Android) intercept that URL and call this endpoint instead, receiving JSON and controlling their own UI.

Parameters:

Response 200: No response body

POST /api/v1/users/me/change-email/{token}/revoke/

Operation: users_me_change_email_revoke_create

Cancel a pending or recently confirmed email change using the token from the notification sent to the old address. Valid for up to 7 days after confirmation. No authentication required – the token is the credential.

On post-confirmation revocation the email is reverted and all active sessions are invalidated.

Dual-path note: See change_email_confirm – the same Universal Link / App Link pattern applies here.

Parameters:

Response 200: No response body

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

GET /api/v1/users/me/invitations/

Operation: users_me_invitations_list

Return all pending co-ownership invitations sent by the authenticated user, across all accounts.

Parameters:

Response 200:

Schemas

APIKey

Read serializer for API keys.

Never exposes the key material – only the displayable prefix. The plaintext key appears exactly once, in the creation response (see APIKeyViewSet.create).

APIKeyCreateRequest

Validate an API-key creation request.

expiry_days covers all the expiry presets (30 / 60 / 90 / 365 / a specific number of days); null or omitted means the key never expires. The presets themselves are a UI concern.

APIKeyCreated

Creation response – the only place the plaintext key appears.

Exists to document the creation response shape in the OpenAPI schema; the view assembles the payload itself. key is never a model field and cannot be recovered after this response.

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.

BankAccountInvitation

Read-only serializer for BankAccountInvitation rows.

token is included so the SPA can construct the cancel URL without a separate lookup. It is safe to expose to authenticated account owners since they created the invitation and the cancel endpoint enforces that only the sender may cancel.

bank_account_id and bank_account_name are included for the cross-account listing on the user’s settings page (me/invitations/).

BankAccountInvitationStatusEnum

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.

The recurrence_schedule’s DTSTART is only the rule’s anchor; this field is the actual upcoming refresh date (first occurrence after last_recurrence_on). Only Recurring budgets have one.

Args: obj: The Budget instance being serialized.

Returns: ISO date string, 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

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

EmailChangeRequestRequest

Validate a request to initiate an email-address change.

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.

FundingEventStatusEnum

FundingPaceEnum

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.

InviteOwnerRequest

Write-only serializer for the invite-owner action.

NotificationPreference

Notification kind preference.

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

NullEnum

PaginatedAPIKeyList

PaginatedBankAccountInvitationList

PaginatedBankAccountList

PaginatedBankList

PaginatedBudgetList

PaginatedChannelPreferenceList

PaginatedFundingEventOccurrenceList

PaginatedInternalTransactionList

PaginatedNotificationPreferenceList

PaginatedTransactionAllocationList

PaginatedTransactionCategoryList

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).

PatchedTransactionCategoryRequest

Serializer for transaction categories.

On create the caller supplies group and name; the view forces the owner to the requesting user (global rows are managed via the django-admin only). Group and name are whitespace-normalized and checked case-insensitively against the global rows and the user’s own rows for duplicates. ‘archived’ is toggled via the archive action, not writable here.

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).

has_usable_password is read-only and used by the SPA to decide whether to enable the change-email and change-password forms.

PublicInvitationDetail

Read-only serializer for the public invitation-detail endpoint.

Returns the minimum information needed to render the acceptance page for API clients. Owner names are intentionally minimal (display name or email only) to limit PII exposure behind a bare token.

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.

ScrapeSyncDetailsNeeded

One posted scrape row still needing a transaction-details fetch.

index is the row’s position in the SUBMITTED transactions array (exact correlation back to the scraper’s own rows); transaction is the DB row the fetched details should be applied to via the transaction-details action.

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.

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.

TransactionCategory

Serializer for transaction categories.

On create the caller supplies group and name; the view forces the owner to the requesting user (global rows are managed via the django-admin only). Group and name are whitespace-normalized and checked case-insensitively against the global rows and the user’s own rows for duplicates. ‘archived’ is toggled via the archive action, not writable here.

TransactionCategoryRequest

Serializer for transaction categories.

On create the caller supplies group and name; the view forces the owner to the requesting user (global rows are managed via the django-admin only). Group and name are whitespace-normalized and checked case-insensitively against the global rows and the user’s own rows for duplicates. ‘archived’ is toggled via the archive action, not writable here.

TransactionDetailsItemRequest

One (transaction, raw details dict) pair to apply.

The details dict is stored verbatim on the transaction (it is the provenance record); the service extracts the merchant columns from it. category is a mibudge category full name (‘{group} : {name}’) – the IMPORTER translates its provider’s vocabulary before submitting; mibudge carries no provider mappings. The name is resolved case-insensitively among the categories visible to the caller; an unknown name yields a per-item warning and the transaction stays unassigned.

TransactionDetailsReport

Output serializer for the bank-account transaction-details action.

TransactionDetailsRequest

Input serializer for the bank-account transaction-details action.

overwrite re-applies scraper-owned fields on rows already enriched (location fields and an assigned category are still never clobbered).

TransactionDetailsResult

Per-item outcome of the transaction-details action.

TransactionDetailsResultStatusEnum

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).

has_usable_password is read-only and used by the SPA to decide whether to enable the change-email and change-password forms.

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).

has_usable_password is read-only and used by the SPA to decide whether to enable the change-email and change-password forms.