Colony API Specification
DOCUMENTATION STATUS
This document is used for initial architecture design and planning of the Colony API endpoints. Once the FastAPI implementation begins, this documentation will be deprecated in favor of the auto-generated OpenAPI/Swagger documentation available at:
- Development:
http://localhost:8000/docs(Swagger UI) - Development:
http://localhost:8000/redoc(ReDoc) - Production:
https://api.colony.app/docs
The purpose of this document is to: - Define the overall API structure and endpoints - Establish request/response schemas - Guide initial development priorities - Serve as a reference during the design phase
For current API documentation, always refer to the auto-generated FastAPI docs.
This document defines the REST API endpoints for the Colony expense management application.
API Overview
- Base URL:
https://api.colony.app/v1 - Authentication: Bearer token (JWT)
- Content-Type:
application/json - API Version: v1
Authentication
All endpoints require authentication except for user registration and login.
Response Format
Success Responses
API endpoints return data directly without wrapper objects. HTTP status codes indicate success or failure.
Error Responses
All errors follow a consistent format:
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human readable error message",
"details": {
// Additional error details if applicable
}
}
}
API Endpoints
1. Authentication & Users
POST /auth/register
Create a new user account. Requires admin role.
Request Body:
{
"username": "alice",
"password": "securePassword123",
"first_name": "Alice",
"last_name": "Smith",
"preferred_currency": "USD",
"locale": "en-US",
"role": "user"
}
Response: 201 Created
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"username": "alice",
"first_name": "Alice",
"last_name": "Smith",
"preferred_currency": "USD",
"locale": "en-US",
"role": "user",
"active": true,
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
Errors: 401 Unauthorized, 403 Forbidden (non-admin),
409 Conflict (username taken)
POST /auth/login
Authenticate user and get access token.
Request Body (Form Data):
Response: 200 OK
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer",
"expires_in": 1800
}
GET /auth/me
Get current user information.
Response: 200 OK
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"username": "alice",
"first_name": "Alice",
"last_name": "Smith",
"preferred_currency": "USD",
"locale": "en-US",
"role": "user",
"active": true,
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
GET /auth/users
List all users. Requires admin role.
Response: 200 OK — array of user objects (same shape as /auth/me).
GET /auth/users/{user_id}
Get a specific user by ID. Requires admin role.
Response: 200 OK — user object.
Errors: 404 Not Found
PUT /auth/users/{user_id}
Update a user. Requires admin role.
Request Body (all fields optional):
{
"first_name": "Alice",
"last_name": "Smith",
"preferred_currency": "USD",
"locale": "en-US",
"role": "admin",
"active": true
}
Response: 200 OK — updated user object.
Errors: 404 Not Found
DELETE /auth/users/{user_id}
Deactivate a user (soft delete). Requires admin role.
Response: 204 No Content
Errors: 404 Not Found
PUT /auth/me
Update current user information.
Request Body:
{
"first_name": "John Updated",
"last_name": "Doe Updated",
"preferred_currency": "MXN",
"locale": "es-MX"
}
Response: 200 OK
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"email": "user@example.com",
"first_name": "John Updated",
"last_name": "Doe Updated",
"preferred_currency": "MXN",
"locale": "es-MX",
"active": true,
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T12:30:00Z"
}
PUT /auth/me/password
Update current user password.
Request Body:
Response: 200 OK
2. Payment Methods
GET /payment-methods
Get all user's payment methods.
Query Parameters:
- active (boolean, optional): Filter by active status
- currency (string, optional): Filter by default currency
Response: 200 OK
[
{
"id": "123e4567-e89b-12d3-a456-426614174001",
"name": "Chase Debit",
"method_type": "debit",
"default_currency": "USD",
"description": "Primary checking account",
"last_4_digits": "4242",
"active": true,
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
},
{
"id": "123e4567-e89b-12d3-a456-426614174002",
"name": "Capital One Credit",
"method_type": "credit",
"default_currency": "USD",
"description": "Rewards credit card",
"last_4_digits": null,
"active": true,
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
]
POST /payment-methods
Create a new payment method.
Request Body:
{
"name": "Capital One Credit",
"method_type": "credit",
"default_currency": "USD",
"description": "Rewards credit card",
"last_4_digits": "4242"
}
Response: 201 Created
{
"id": "123e4567-e89b-12d3-a456-426614174002",
"name": "Capital One Credit",
"method_type": "credit",
"default_currency": "USD",
"description": "Rewards credit card",
"last_4_digits": "4242",
"active": true,
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
GET /payment-methods/{id}
Get a specific payment method.
Response: 200 OK
{
"id": "123e4567-e89b-12d3-a456-426614174001",
"name": "Chase Debit",
"method_type": "debit",
"default_currency": "USD",
"description": "Primary checking account",
"last_4_digits": "4242",
"active": true,
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
PUT /payment-methods/{id}
Update an existing payment method.
Request Body:
{
"name": "Chase Debit Updated",
"description": "Updated description",
"last_4_digits": "4242",
"active": true
}
Response: 200 OK
{
"id": "123e4567-e89b-12d3-a456-426614174001",
"name": "Chase Debit Updated",
"method_type": "debit",
"default_currency": "USD",
"description": "Updated description",
"last_4_digits": "4242",
"active": true,
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T12:30:00Z"
}
DELETE /payment-methods/{id}
Deactivate a payment method (soft delete).
Response: 204 No Content
3. Recurrent Expenses
GET /recurrent-expenses
Get all user's recurrent expenses.
Query Parameters:
- active (boolean, optional): Filter by active status
- category (string, optional): Filter by category (fixed/variable/extra)
- currency (string, optional): Filter by currency
Response: 200 OK
[
{
"id": "123e4567-e89b-12d3-a456-426614174003",
"description": "Rent",
"currency": "USD",
"base_amount": "1200.00",
"category": "fixed",
"recurrence_type": "monthly",
"recurrence_config": {
"day_of_month": 1
},
"reference_date": "2024-12-01",
"autopay": true,
"active": true,
"payment_method": {
"id": "123e4567-e89b-12d3-a456-426614174001",
"name": "Chase Debit",
"method_type": "debit"
},
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
]
POST /recurrent-expenses
Create a new recurrent expense.
Request Body:
{
"description": "Groceries",
"currency": "USD",
"payment_method_id": "123e4567-e89b-12d3-a456-426614174001",
"base_amount": "150.00",
"category": "variable",
"recurrence_type": "weekly",
"recurrence_config": {
"day_of_week": 6
},
"reference_date": "2024-12-21",
"autopay": false
}
Response: 201 Created
{
"id": "123e4567-e89b-12d3-a456-426614174004",
"description": "Groceries",
"currency": "USD",
"base_amount": "150.00",
"category": "variable",
"recurrence_type": "weekly",
"recurrence_config": {
"day_of_week": 6
},
"reference_date": "2024-12-21",
"autopay": false,
"active": true,
"payment_method": {
"id": "123e4567-e89b-12d3-a456-426614174001",
"name": "Chase Debit",
"method_type": "debit"
},
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
GET /recurrent-expenses/{id}
Get a specific recurrent expense.
PUT /recurrent-expenses/{id}
Update a recurrent expense.
DELETE /recurrent-expenses/{id}
Delete a recurrent expense.
Response: 204 No Content
4. Recurrent Incomes
GET /recurrent-incomes
Get all recurrent income templates for the current user.
Query Parameters:
active(boolean, optional): Filter by active statuscurrency(string, optional): Filter by currency
Response: 200 OK
[
{
"id": "aaa11111-e89b-12d3-a456-426614174001",
"description": "Monthly Salary",
"base_amount": "3500.00",
"currency": "USD",
"recurrence_type": "monthly",
"recurrence_config": { "day_of_month": 15 },
"reference_date": "2025-01-15",
"payment_method": {
"id": "123e4567-e89b-12d3-a456-426614174001",
"name": "Chase Debit",
"method_type": "debit"
},
"active": true,
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
]
POST /recurrent-incomes
Create a new recurrent income template.
Request Body:
{
"description": "Monthly Salary",
"base_amount": "3500.00",
"currency": "USD",
"recurrence_type": "monthly",
"recurrence_config": { "day_of_month": 15 },
"reference_date": "2025-01-15",
"payment_method_id": "123e4567-e89b-12d3-a456-426614174001"
}
Response: 201 Created — same shape as list item above.
Error Codes:
| Code | Status | Description |
|---|---|---|
PAYMENT_METHOD_NOT_FOUND |
404 | Payment method not found or not owned |
INVALID_RECURRENCE_CONFIG |
422 | Config does not match recurrence type |
GET /recurrent-incomes/{id}
Get a specific recurrent income template.
Response: 200 OK — same shape as list item.
Error Codes:
| Code | Status | Description |
|---|---|---|
RECURRENT_INCOME_NOT_FOUND |
404 | Income template not found |
PUT /recurrent-incomes/{id}
Update a recurrent income template. All fields optional.
Request Body:
Response: 200 OK — updated template.
DELETE /recurrent-incomes/{id}
Soft-delete (deactivate) a recurrent income template.
Response: 204 No Content
5. Cycles
GET /cycles
Get all user's cycles with pagination.
Query Parameters:
- status (string, optional): Filter by status (draft/active/completed)
- page (integer, optional): Page number (default: 1)
- per_page (integer, optional): Items per page (default: 20, max: 100)
Response: 200 OK
{
"cycles": [
{
"id": "123e4567-e89b-12d3-a456-426614174004",
"name": "January 2025 Cycle",
"start_date": "2025-01-01",
"end_date": "2025-02-11",
"remaining_balance": "500.00",
"status": "active",
"summary": {
"total_expenses": "4500.00",
"fixed_expenses": "3000.00",
"variable_expenses": "1500.00",
"expense_count": 25,
"paid_count": 10,
"pending_count": 15
},
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
],
"pagination": {
"page": 1,
"per_page": 20,
"total": 1,
"pages": 1
}
}
POST /cycles
Create a new cycle.
Request Body:
{
"name": "February 2025 Cycle",
"start_date": "2025-02-12",
"end_date": "2025-03-25",
"generate_from_templates": true
}
Response: 201 Created
{
"id": "123e4567-e89b-12d3-a456-426614174005",
"name": "February 2025 Cycle",
"start_date": "2025-02-12",
"end_date": "2025-03-25",
"remaining_balance": "0.00",
"status": "draft",
"summary": {
"total_expenses": "0.00",
"fixed_expenses": "0.00",
"variable_expenses": "0.00",
"expense_count": 0,
"paid_count": 0,
"pending_count": 0
},
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
GET /cycles/{id}
Get a specific cycle with detailed information.
Response: 200 OK
{
"id": "123e4567-e89b-12d3-a456-426614174004",
"name": "January 2025 Cycle",
"start_date": "2025-01-01",
"end_date": "2025-02-11",
"remaining_balance": "500.00",
"status": "active",
"summary": {
"total_expenses": "4500.00",
"fixed_expenses": "3000.00",
"variable_expenses": "1500.00",
"expense_count": 25,
"paid_count": 10,
"pending_count": 15
},
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
PUT /cycles/{id}
Update a cycle.
Request Body:
Response: 200 OK
DELETE /cycles/{id}
Delete a cycle and all associated expenses.
Response: 204 No Content
GET /cycles/{cycle_id}/expenses
Get all expenses for a specific cycle.
Query Parameters:
- status (string, optional): Filter by status
(pending/paid/cancelled/overdue/paid_other/skipped)
- category (string, optional): Filter by category (fixed/variable/extra)
- currency (string, optional): Filter by currency
- payment_method_id (string, optional): Filter by payment method
Response: 200 OK
{
"expenses": [
{
"id": "123e4567-e89b-12d3-a456-426614174005",
"description": "Rent",
"currency": "USD",
"amount": "1200.00",
"amount_usd": "1200.00",
"due_date": "2025-01-01",
"category": "fixed",
"status": "paid",
"paid": true,
"paid_at": "2025-01-01T08:00:00Z",
"comments": "Paid on time",
"autopay": true,
"template_id": "123e4567-e89b-12d3-a456-426614174003",
"payment_method": {
"id": "123e4567-e89b-12d3-a456-426614174001",
"name": "Chase Debit",
"method_type": "debit"
},
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T08:00:00Z"
}
],
"summary": {
"total_amount_usd": "1200.00",
"fixed_amount": "1200.00",
"variable_amount": "0.00",
"extra_amount": "0.00",
"paid_amount": "1200.00",
"pending_amount": "0.00",
"total_count": 1
}
}
POST /cycles/{cycle_id}/expenses
Add a manual expense to a cycle. Category is always set to extra
automatically — it cannot be specified by the caller.
Request Body:
{
"description": "Emergency car repair",
"currency": "USD",
"payment_method_id": "123e4567-e89b-12d3-a456-426614174002",
"amount": "350.00",
"due_date": "2025-01-15",
"comments": "Unexpected expense",
"paid": false
}
paid is optional (default false). When true, the expense is created
with status paid and paid_at set to the current timestamp.
Response: 201 Created
{
"id": "123e4567-e89b-12d3-a456-426614174006",
"description": "Emergency car repair",
"currency": "USD",
"amount": "350.00",
"amount_usd": "350.00",
"due_date": "2025-01-15",
"category": "extra",
"status": "pending",
"paid": false,
"paid_at": null,
"autopay": false,
"template_id": null,
"payment_method": {
"id": "123e4567-e89b-12d3-a456-426614174002",
"name": "Capital One Credit",
"method_type": "credit"
},
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
GET /cycles/{cycle_id}/expenses/{expense_id}
Get a specific expense.
PUT /cycles/{cycle_id}/expenses/{expense_id}
Update an expense.
Request Body:
{
"amount": "375.00",
"paid": true,
"paid_at": "2025-01-15T14:30:00Z",
"comments": "Updated amount and marked as paid"
}
Response: 200 OK
DELETE /cycles/{cycle_id}/expenses/{expense_id}
Delete an expense from a cycle.
Response: 204 No Content
GET /cycles/{cycle_id}/incomes
List all income entries for a cycle (auto-generated + manual).
Response: 200 OK
[
{
"id": "bbb22222-e89b-12d3-a456-426614174001",
"cycle_id": "123e4567-e89b-12d3-a456-426614174004",
"template_id": "aaa11111-e89b-12d3-a456-426614174001",
"description": "Monthly Salary",
"amount": "3500.00",
"amount_usd": "3500.00",
"currency": "USD",
"income_date": "2025-01-15",
"payment_method": {
"id": "123e4567-e89b-12d3-a456-426614174001",
"name": "Chase Debit",
"method_type": "debit"
},
"comments": null,
"active": true,
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
},
{
"id": "bbb33333-e89b-12d3-a456-426614174002",
"cycle_id": "123e4567-e89b-12d3-a456-426614174004",
"template_id": null,
"description": "Freelance bonus",
"amount": "500.00",
"amount_usd": "500.00",
"currency": "USD",
"income_date": "2025-01-20",
"payment_method": null,
"comments": "One-time project",
"active": true,
"created_at": "2025-01-20T00:00:00Z",
"updated_at": "2025-01-20T00:00:00Z"
}
]
POST /cycles/{cycle_id}/incomes
Add a manual income entry to a cycle.
Request Body:
{
"description": "Freelance bonus",
"amount": "500.00",
"currency": "USD",
"income_date": "2025-01-20",
"payment_method_id": null,
"comments": "One-time project"
}
Response: 201 Created — same shape as list item above.
Error Codes:
| Code | Status | Description |
|---|---|---|
CYCLE_NOT_FOUND |
404 | Cycle not found |
CYCLE_INCOME_NOT_FOUND |
404 | Income entry not found |
PUT /cycles/{cycle_id}/incomes/{income_id}
Update a cycle income entry. All fields optional.
Response: 200 OK — updated income entry.
DELETE /cycles/{cycle_id}/incomes/{income_id}
Soft-delete an income entry from a cycle. Recalculates remaining_balance.
Response: 204 No Content
GET /cycles/{cycle_id}/summary
Get detailed cycle summary and analytics.
Response: 200 OK
{
"cycle": {
"id": "123e4567-e89b-12d3-a456-426614174004",
"name": "January 2025 Cycle",
"start_date": "2025-01-01",
"end_date": "2025-02-11"
},
"financial": {
"total_expenses_usd": "4500.00",
"fixed_expenses_usd": "3000.00",
"variable_expenses_usd": "1500.00",
"extra_expenses_usd": "0.00",
"usa_expenses_usd": "3800.00",
"mexico_expenses_usd": "700.00",
"total_incomes_usd": "4000.00",
"net_balance": "4500.00"
},
"incomes": [
{
"id": "bbb22222-e89b-12d3-a456-426614174001",
"template_id": "aaa11111-e89b-12d3-a456-426614174001",
"description": "Monthly Salary",
"amount": "3500.00",
"amount_usd": "3500.00",
"currency": "USD",
"income_date": "2025-01-15",
"payment_method": null,
"comments": null,
"active": true,
"created_at": "2025-01-01T00:00:00Z",
"updated_at": "2025-01-01T00:00:00Z"
}
],
"by_payment_method": [
{
"payment_method": {
"id": "123e4567-e89b-12d3-a456-426614174001",
"name": "Chase Debit"
},
"total_amount": "2500.00",
"paid_amount": "1500.00",
"pending_amount": "1000.00",
"expense_count": 15
}
],
"by_currency": {
"USD": {
"total_amount": "3800.00",
"expense_count": 20
},
"MXN": {
"total_amount": "14000.00",
"total_amount_usd": "700.00",
"expense_count": 5
}
},
"status_breakdown": {
"pending": 15,
"paid": 8,
"overdue": 2,
"cancelled": 0,
"paid_other": 1,
"skipped": 1
}
}
Note on
overduecount: Theoverduevalue instatus_breakdownis derived at request time, not read from the storedstatuscolumn. Any expense whose stored status ispendingand whosedue_dateis earlier than today is counted asoverdue(and removed frompending). This matches the per-expense overdue derivation applied in individual expense responses.Note on
paid_otherandskipped: Both statuses are excluded fromtotal_expenses_usdand from the remaining balance calculation, the same ascancelled. Usepaid_otherwhen an expense was covered by a third party (not from tracked income). Useskippedwhen the expense was not applicable for the current cycle.Note on
net_balance:net_balance = total_incomes_usd − total_expenses_usd
6. Activity & Comments
JIRA-style history feed and Markdown comments attached polymorphically
to any entity (payment_method, recurrent_expense, recurrent_income,
cycle, cycle_expense, cycle_income). See
activity-log.md for the full data model.
GET /activity
Activity feed filtered by entity or cycle.
Query Parameters:
entity_type(string, optional) — combined withentity_identity_id(uuid, optional)cycle_id(uuid, optional) — alternative scopebefore(datetime, optional) — cursor; returns rows withcreated_at < beforelimit(int, default 50, max 200)
Requires at least one scope (entity or cycle); requests with no scope
return [] to avoid leaking the household-wide feed.
GET /comments
Same query parameters as /activity but only returns user comments.
POST /comments
Create a comment.
Body:
Returns 201 CREATED with the created comment. Records a
commented activity event.
PATCH /comments/{comment_id}
Edit a comment body. Author only — non-authors get 403.
DELETE /comments/{comment_id}
Soft-delete a comment (sets active=False). Allowed for the author or
any user with role == "admin". Returns 204 NO CONTENT.
7. Reports & Analytics
GET /reports/cycles-comparison
Compare multiple cycles.
Query Parameters:
- cycle_ids (array, required): Comma-separated cycle IDs
- metrics (array, optional): Specific metrics to compare
Response: 200 OK
{
"cycles": [
{
"cycle": {
"id": "123e4567-e89b-12d3-a456-426614174004",
"name": "January 2025 Cycle"
},
"metrics": {
"total_expenses": "4500.00",
"fixed_expenses": "3000.00",
"variable_expenses": "1500.00"
}
}
],
"comparison": {
"average_total": "4500.00",
"trends": {
"expenses": "stable"
}
}
}
8. System Endpoints
GET /enums
Get all system enums for form validation.
Response: 200 OK
{
"currency_codes": ["USD", "MXN"],
"payment_method_types": ["debit", "credit", "cash", "transfer"],
"expense_categories": ["fixed", "variable"],
"recurrence_types": ["weekly", "bi_weekly", "monthly", "custom"],
"cycle_statuses": ["draft", "active", "completed"],
"expense_statuses": ["pending", "paid", "cancelled", "overdue", "paid_other", "skipped"]
}
GET /exchange-rates/
List all exchange rates ordered by date descending.
Auth required: Yes
Response: 200 OK
[
{
"id": "uuid",
"from_currency": "MXN",
"to_currency": "USD",
"rate": "0.052000",
"rate_date": "2025-01-15",
"created_at": "2025-01-15T10:00:00Z"
}
]
POST /exchange-rates/
Create a new exchange rate record.
Auth required: Yes
Request Body:
Response: 201 Created — the created exchange rate object.
Errors:
409 EXCHANGE_RATE_DATE_EXISTS— a rate for this currency pair and date already exists.
PUT /exchange-rates/{rate_id}
Update the rate value of an existing exchange rate record.
Only the rate field is mutable; the date is immutable.
Auth required: Yes
Request Body:
Response: 200 OK — the updated exchange rate object.
Errors:
404— exchange rate not found.
GET /health
System health check.
Response: 200 OK
{
"status": "healthy",
"service": "colony-api",
"version": "1.0.0",
"timestamp": "2025-01-01T00:00:00Z"
}
Error Codes
| Code | HTTP Status | Description |
|---|---|---|
VALIDATION_ERROR |
400 | Request validation failed |
USER_NOT_FOUND |
404 | User not found |
USER_ALREADY_EXISTS |
409 | User already exists |
INVALID_CREDENTIALS |
401 | Invalid email or password |
INVALID_TOKEN |
401 | Invalid or expired token |
INACTIVE_USER |
403 | User account is inactive |
INCORRECT_PASSWORD |
400 | Current password is incorrect |
RESOURCE_NOT_FOUND |
404 | Requested resource not found |
RESOURCE_CONFLICT |
409 | Resource conflict (e.g., duplicate name) |
CURRENCY_CONVERSION_ERROR |
422 | Failed to convert currency |
CYCLE_GENERATION_ERROR |
422 | Failed to generate cycle expenses |
EXCHANGE_RATE_NOT_FOUND |
422 | No exchange rate available for the currency pair |
EXCHANGE_RATE_DATE_EXISTS |
409 | Rate for that currency pair and date already exists |
COMMENT_NOT_FOUND |
404 | Comment not found |
COMMENT_NOT_AUTHOR |
403 | Only the author can edit this comment |
COMMENT_DELETE_FORBIDDEN |
403 | Only the author or an admin can delete this comment |
INVALID_ENTITY_TYPE |
400 | Polymorphic entity_type is not commentable |
INVALID_ENTITY_REFERENCE |
404 | (entity_type, entity_id) does not exist in this household |
COMMENT_BODY_REQUIRED |
400 | Comment body cannot be empty |
INTERNAL_SERVER_ERROR |
500 | Server error |
HTTP Status Codes
200 OK- Successful GET, PUT requests201 Created- Successful POST requests (resource created)204 No Content- Successful DELETE requests400 Bad Request- Invalid request data401 Unauthorized- Authentication required or invalid token403 Forbidden- Insufficient permissions404 Not Found- Resource not found409 Conflict- Resource conflict422 Unprocessable Entity- Validation error or business logic error500 Internal Server Error- Server error
Rate Limiting
- Authenticated requests: 1000 requests per hour
- Authentication endpoints: 10 requests per minute
- Report generation: 100 requests per hour
Data Validation Rules
Currency Amounts
- Must be positive decimal numbers
- Maximum 2 decimal places
- Maximum value: 999,999,999.99
Dates
- Format: YYYY-MM-DD
- Cycle end_date must be after start_date
- Reference dates can be in the past
Text Fields
- Description: 1-255 characters
- Name: 1-100 characters
- Comments: 0-1000 characters
API Usage Examples
Creating a Complete Expense Cycle
- Create Payment Methods (if not exists)
- Create Recurrent Expenses
- Create Cycle with automatic template generation
- Modify Generated Expenses as needed
- Track Payment Status throughout the cycle
- Generate Reports for analysis
Example Workflow
// 1. Create payment method
const paymentMethodResponse = await fetch('/api/v1/payment-methods', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token
},
body: JSON.stringify({
name: 'Chase Debit',
method_type: 'debit',
default_currency: 'USD'
})
});
const paymentMethod = await paymentMethodResponse.json();
// 2. Create recurrent expense
const templateResponse = await fetch('/api/v1/recurrent-expenses', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token
},
body: JSON.stringify({
description: 'Rent',
currency: 'USD',
payment_method_id: paymentMethod.id,
base_amount: '1200.00',
category: 'fixed',
recurrence_type: 'monthly',
recurrence_config: { day_of_month: 1 },
reference_date: '2024-12-01'
})
});
// 3. Create cycle
const cycleResponse = await fetch('/api/v1/cycles', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token
},
body: JSON.stringify({
name: 'February 2025 Cycle',
start_date: '2025-02-01',
end_date: '2025-03-14',
generate_from_templates: true
})
});
const cycle = await cycleResponse.json();
// 4. Get cycle summary
const summaryResponse = await fetch(`/api/v1/cycles/${cycle.id}/summary`, {
headers: {
'Authorization': 'Bearer ' + token
}
});
const summary = await summaryResponse.json();