跳到主要内容

Developer API Reference

Overview

The Accounts API provides RESTful endpoints for managing financial accounts in UnderControl. All endpoints require authentication via Bearer token.

Authentication

All account endpoints require JWT authentication:

Authorization: Bearer <access_token>

Base URL

https://api.undercontrol.app

For local development:

http://localhost:8898

Endpoints

List User Accounts

Retrieve all accounts belonging to the authenticated user.

Endpoint: GET /account

Response: 200 OK

{
"accounts": [
{
"id": "uuid-string",
"owner_id": "user-uuid",
"name": "Checking Account",
"balance": {
"amount": 5000.00,
"currency": "USD"
},
"notes": "Primary checking",
"tags": ["primary", "checking"],
"off_budget": false,
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-20T14:45:00Z"
}
],
"count": 1
}

Get Account Homepage

Retrieve aggregated account data for the homepage view.

Endpoint: GET /account/homepage

Response: 200 OK

{
"accountCount": 5,
"total": 15000.00,
"budgetTotal": 10000.00,
"offBudgetTotal": 5000.00,
"budgetAccounts": [
{
"id": "uuid-string",
"name": "Checking",
"balance": {
"amount": 5000.00,
"currency": "USD"
},
"off_budget": false,
"tags": [],
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-20T14:45:00Z"
}
],
"offBudgetAccounts": [
{
"id": "uuid-string",
"name": "Investment",
"balance": {
"amount": 5000.00,
"currency": "USD"
},
"off_budget": true,
"tags": ["investment"],
"created_at": "2024-01-10T09:00:00Z",
"updated_at": "2024-01-18T11:30:00Z"
}
]
}

Create Account

Create a new account for the authenticated user.

Endpoint: POST /account

Request Body:

{
"name": "Savings Account",
"balance": {
"amount": 1000.00,
"currency": "USD"
},
"notes": "Emergency fund",
"off_budget": true
}

Validation Rules:

  • name: Required, 1-100 characters
  • balance: Required, valid Money object
  • notes: Optional, max 500 characters
  • off_budget: Optional, defaults to false

Response: 201 Created

{
"id": "new-uuid-string",
"owner_id": "user-uuid",
"name": "Savings Account",
"balance": {
"amount": 1000.00,
"currency": "USD"
},
"notes": "Emergency fund",
"tags": [],
"off_budget": true,
"created_at": "2024-01-25T16:00:00Z",
"updated_at": "2024-01-25T16:00:00Z"
}

Get Account by ID

Retrieve a specific account by its ID.

Endpoint: GET /account/{id}

Path Parameters:

  • id: Account UUID (required)

Response: 200 OK

{
"id": "uuid-string",
"owner_id": "user-uuid",
"name": "Checking Account",
"balance": {
"amount": 5000.00,
"currency": "USD"
},
"notes": "Primary checking",
"tags": ["primary", "checking"],
"off_budget": false,
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-20T14:45:00Z"
}

Error Response: 404 Not Found

{
"error": "Account not found"
}

Get Account Details with History

Retrieve account with complete history of changes.

Endpoint: GET /account/{id}/details

Path Parameters:

  • id: Account UUID (required)

Response: 200 OK

{
"account": {
"id": "uuid-string",
"owner_id": "user-uuid",
"name": "Checking Account",
"balance": {
"amount": 5000.00,
"currency": "USD"
},
"notes": "Primary checking",
"tags": ["primary", "checking"],
"off_budget": false,
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-20T14:45:00Z"
},
"histories": [
{
"id": "history-uuid-1",
"account_id": "uuid-string",
"owner_id": "user-uuid",
"name": "Checking Account",
"balance": {
"amount": 4500.00,
"currency": "USD"
},
"notes": "Primary checking",
"tags": ["primary", "checking"],
"off_budget": false,
"created_at": "2024-01-20T14:45:00Z",
"updated_at": "2024-01-20T14:45:00Z"
},
{
"id": "history-uuid-2",
"account_id": "uuid-string",
"owner_id": "user-uuid",
"name": "Checking Account",
"balance": {
"amount": 3000.00,
"currency": "USD"
},
"notes": "Primary checking",
"tags": ["primary"],
"off_budget": false,
"created_at": "2024-01-18T09:00:00Z",
"updated_at": "2024-01-18T09:00:00Z"
}
]
}

Update Account

Update an existing account's details.

Endpoint: PUT /account/{id}

Path Parameters:

  • id: Account UUID (required)

Request Body:

{
"name": "Updated Account Name",
"balance": {
"amount": 6000.00,
"currency": "USD"
},
"notes": "Updated notes",
"off_budget": false
}

Note: All fields are optional. Only provided fields will be updated.

Response: 200 OK

{
"id": "uuid-string",
"owner_id": "user-uuid",
"name": "Updated Account Name",
"balance": {
"amount": 6000.00,
"currency": "USD"
},
"notes": "Updated notes",
"tags": ["primary", "checking"],
"off_budget": false,
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-25T17:00:00Z"
}

Delete Account

Permanently delete an account.

Endpoint: DELETE /account/{id}

Path Parameters:

  • id: Account UUID (required)

Response: 204 No Content

Error Response: 404 Not Found

{
"error": "Account not found"
}

Data Models

AccountResponseDTO

interface AccountResponseDTO {
id: string;
owner_id: string;
name: string;
balance: MoneyDTO;
notes?: string;
tags: string[];
off_budget: boolean;
created_at: string;
updated_at: string;
}

MoneyDTO

interface MoneyDTO {
amount: number;
currency: string;
}

CreateAccountDTO

interface CreateAccountDTO {
name: string; // Required, 1-100 characters
balance: MoneyDTO; // Required
notes?: string; // Optional, max 500 characters
off_budget?: boolean; // Optional, defaults to false
}

UpdateAccountDTO

interface UpdateAccountDTO {
name?: string; // Optional, 1-100 characters
balance?: MoneyDTO; // Optional
notes?: string; // Optional, max 500 characters
off_budget?: boolean; // Optional
}

AccountHomepageResponseDTO

interface AccountHomepageResponseDTO {
accountCount: number;
total: number;
budgetTotal: number;
offBudgetTotal: number;
budgetAccounts: AccountResponseDTO[];
offBudgetAccounts: AccountResponseDTO[];
}

AccountDetailsResponseDTO

interface AccountDetailsResponseDTO {
account: AccountResponseDTO;
histories: AccountHistoryResponseDTO[];
}

AccountHistoryResponseDTO

interface AccountHistoryResponseDTO {
id: string;
account_id: string;
owner_id: string;
name: string;
balance: MoneyDTO;
notes?: string;
tags: string[];
off_budget: boolean;
created_at: string;
updated_at: string;
}

Error Responses

All endpoints may return the following error responses:

400 Bad Request

{
"error": "Validation error message",
"code": "VALIDATION_ERROR"
}

401 Unauthorized

{
"error": "Authentication required",
"code": "AUTH_REQUIRED"
}

403 Forbidden

{
"error": "Access denied",
"code": "ACCESS_DENIED"
}

404 Not Found

{
"error": "Resource not found",
"code": "NOT_FOUND"
}

500 Internal Server Error

{
"error": "Internal server error",
"code": "INTERNAL_ERROR"
}

Rate Limiting

API endpoints are rate-limited to prevent abuse:

  • 100 requests per minute per user
  • 1000 requests per hour per user

Rate limit headers are included in responses:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1706186400

Examples

cURL Examples

List all accounts:

curl -X GET https://api.undercontrol.app/account \
-H "Authorization: Bearer YOUR_TOKEN"

Create a new account:

curl -X POST https://api.undercontrol.app/account \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "New Savings",
"balance": {
"amount": 1000.00,
"currency": "USD"
},
"off_budget": true
}'

Update an account:

curl -X PUT https://api.undercontrol.app/account/ACCOUNT_ID \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"balance": {
"amount": 1500.00,
"currency": "USD"
}
}'

JavaScript/TypeScript Example

import { apiClient } from '@/lib/api/api-client';

// List accounts
const accounts = await apiClient.account.getUserAccounts();

// Create account
const newAccount = await apiClient.account.createAccount({
name: "Emergency Fund",
balance: {
amount: 5000,
currency: "USD"
},
notes: "For emergencies only",
off_budget: true
});

// Update account
const updated = await apiClient.account.updateAccount(accountId, {
balance: {
amount: 5500,
currency: "USD"
}
});

// Delete account
await apiClient.account.deleteAccount(accountId);