Skip to main content

Overview

The Budgets API allows users to set spending limits for specific categories over a defined time period. The API automatically calculates spending progress, alerts for exceeded budgets, and tracks remaining days.
Budgets are tracked against expense transactions (type='chi') within the specified date range and category filters.

Authentication

All endpoints require session-based authentication via the @api_login_required decorator.

Get All Budgets

Retrieve all budgets for the authenticated user with real-time spending calculations. Endpoint: GET /api/budgets

Response

Returns an array of budget objects with calculated spending progress.
[
  {
    "id": "bgt12345",
    "name": "Monthly Groceries",
    "amount": 5000000,
    "spent": 3200000,
    "progress": 64.0,
    "is_exceeded": false,
    "start_date": "2026-03-01",
    "end_date": "2026-03-31",
    "days_left": 24,
    "categories": [
      { "id": "cat001", "name": "Groceries" },
      { "id": "cat002", "name": "Dining Out" }
    ]
  }
]

Response Fields

id
string
Unique 8-character budget ID
name
string
Budget name (e.g., “Monthly Entertainment Budget”)
amount
float
Budget limit in VND
spent
float
Total amount spent so far (calculated from transactions)
progress
float
Spending progress percentage (0-100, capped at 100)
is_exceeded
boolean
True if spending exceeds the budget limit
start_date
string
Budget start date (YYYY-MM-DD format)
end_date
string
Budget end date (YYYY-MM-DD format)
days_left
integer
Number of days remaining (minimum 0)
categories
array
List of categories tracked by this budget

Example Request

curl -X GET https://api.finai.com/api/budgets \
  -H "Cookie: session=your_session_cookie"

Create Budget

Create a new budget with spending limits and category tracking. Endpoint: POST /api/budgets

Request Body

name
string
required
Budget name (e.g., “Q1 Marketing Budget”)
amount
float
required
Budget limit amount in VND
start_date
string
required
Start date in YYYY-MM-DD format
end_date
string
required
End date in YYYY-MM-DD format
category_ids
array
required
Array of category IDs to track (e.g., ["cat001", "cat002"])

Example Request

curl -X POST https://api.finai.com/api/budgets \
  -H "Content-Type: application/json" \
  -H "Cookie: session=your_session_cookie" \
  -d '{
    "name": "Monthly Food Budget",
    "amount": 3000000,
    "start_date": "2026-03-01",
    "end_date": "2026-03-31",
    "category_ids": ["abc12345", "def67890"]
  }'

Response

{
  "status": "success",
  "message": "Đã tạo ngân sách!"
}

Error Response

{
  "status": "error",
  "message": "Error description"
}

Delete Budget

Delete an existing budget. Endpoint: DELETE /api/budgets/{budget_id}

Path Parameters

budget_id
string
required
The unique budget ID to delete

Example Request

curl -X DELETE https://api.finai.com/api/budgets/bgt12345 \
  -H "Cookie: session=your_session_cookie"

Response

{
  "status": "success"
}

Implementation Details

Spending Calculation

The API calculates spending by summing all expense transactions that match:
  1. User ID: Belongs to the authenticated user
  2. Transaction Type: type='chi' (expenses only)
  3. Category Match: category_id is in the budget’s tracked categories
  4. Date Range: Transaction date falls between start_date and end_date
budget.py
spent = db.session.query(func.sum(Transaction.amount)).filter(
    Transaction.user_id == user_id,
    Transaction.type == 'chi',
    Transaction.category_id.in_(cat_ids),
    Transaction.date >= b.start_date,
    Transaction.date <= b.end_date
).scalar() or 0

Progress Calculation

Progress percentage is calculated as:
progress = (spent / limit_amount) * 100 if limit_amount > 0 else 0
progress = min(progress, 100)  # Capped at 100%

Days Remaining

Days left is calculated from today’s date:
days_left = (b.end_date - today).days
days_left = max(days_left, 0)  # Never negative

Database Schema

Budgets use a many-to-many relationship with categories through the ngansach_danhmuc association table:
models.py
class Budget(db.Model):
    __tablename__ = 'ngansach'
    
    id = db.Column('MaNganSach', db.String(8), primary_key=True)
    user_id = db.Column('MaNguoiDung', db.String(8), db.ForeignKey('nguoidung.MaNguoiDung', ondelete='CASCADE'), nullable=False)
    name = db.Column('TenNganSach', db.String(100), nullable=False)
    limit_amount = db.Column('SoTienGioiHan', db.Float, nullable=False)
    start_date = db.Column('NgayBatDau', db.Date, nullable=False)
    end_date = db.Column('NgayKetThuc', db.Date, nullable=False)
    created_at = db.Column('NgayTao', db.DateTime, default=datetime.now)
    
    # Many-to-Many with Category
    categories = db.relationship('Category', secondary=budget_category, backref=db.backref('budgets', lazy=True))

Build docs developers (and LLMs) love