Version: 1.0.0 | Base URL: https://api.family-office.com/api/v1 | Auth: Bearer JWT
The Family Office API is a RESTful service built with FastAPI. All requests and responses use JSON. Authentication uses short-lived JWT access tokens (60 min) paired with long-lived refresh tokens (30 days).
Production: https://api.family-office.com/api/v1
Staging: https://staging-api.family-office.com/api/v1
Local: http://localhost:8000/api/v1
Include the access token in every protected request:
Authorization: Bearer <access_token>{
"id": "uuid",
"created_at": "2024-10-24T12:00:00Z",
...data fields
}{
"detail": "Human-readable error message"
}| Endpoint group | Limit |
|---|---|
| General API | 60 req/min |
| Auth (login/register) | 10 req/min |
| File uploads | 20 req/min |
Create a new user account.
Request Body:
{
"full_name": "Julian Sterling",
"email": "julian@sterling.com",
"password": "SecurePass123!"
}Response 201:
{
"id": "a1b2c3d4-...",
"full_name": "Julian Sterling",
"email": "julian@sterling.com",
"role": "member",
"avatar_url": null,
"is_active": true,
"is_verified": false,
"created_at": "2024-10-24T10:00:00Z"
}Errors: 409 email already exists | 422 validation error
Authenticate and receive JWT token pair.
Request Body:
{
"email": "julian@sterling.com",
"password": "SecurePass123!"
}Response 200:
{
"access_token": "eyJ0eXAiOiJKV1Qi...",
"refresh_token": "eyJ0eXAiOiJKV1Qi...",
"token_type": "bearer",
"expires_in": 3600
}Errors: 401 invalid credentials | 403 account disabled
Exchange a refresh token for a new access token.
Request Body:
{ "refresh_token": "eyJ0eXAiOiJKV1Qi..." }Response 200: Same as /auth/login
Returns the current user's profile. Requires auth.
Response 200: Same as register response.
Create a new family. Caller becomes the admin.
Request Body:
{
"name": "The Sterling Family",
"description": "Our family wealth management account",
"currency": "USD",
"timezone": "America/New_York"
}Response 201:
{
"id": "f1a2b3c4-...",
"name": "The Sterling Family",
"currency": "USD",
"timezone": "America/New_York",
"plan": "free",
"created_at": "2024-10-24T10:00:00Z"
}Get family details. Requires family membership.
Response 200: Family object (see above)
Update family details. Requires admin role.
Request Body (all fields optional):
{
"name": "Sterling Family Office",
"currency": "GBP"
}List all family members.
Response 200:
[
{
"id": "m1b2c3-...",
"user_id": "u1b2c3-...",
"family_id": "f1b2c3-...",
"role": "admin",
"display_name": "Julian",
"joined_at": "2024-10-01T00:00:00Z"
}
]Invite a user by email. Requires admin role.
Request Body:
{
"email": "clarissa@sterling.com",
"role": "member",
"display_name": "Clarissa"
}Member roles: admin | member | dependent | advisor
Errors: 404 email not found | 409 already a member
Remove a member. Requires admin role. Cannot remove self.
Response: 204 No Content
All transaction endpoints are scoped to a family:
/families/{family_id}/transactions
Request Body:
{
"type": "expense",
"amount": 245.50,
"currency": "USD",
"description": "Whole Foods Market",
"notes": "Weekly grocery shop",
"category_id": "cat-uuid",
"transaction_date": "2024-10-24T14:30:00Z",
"merchant_name": "Whole Foods"
}Transaction types: income | expense | transfer
Response 201:
{
"id": "tx-uuid",
"family_id": "fam-uuid",
"user_id": "user-uuid",
"category_id": "cat-uuid",
"type": "expense",
"status": "completed",
"amount": "245.50",
"currency": "USD",
"description": "Whole Foods Market",
"transaction_date": "2024-10-24T14:30:00Z",
"receipt_url": null,
"is_anomaly": false,
"is_ocr_generated": false,
"created_at": "2024-10-24T14:35:00Z"
}Query Parameters:
| Parameter | Type | Description |
|---|---|---|
page |
int | Page number (default: 1) |
page_size |
int | Items per page (default: 20, max: 100) |
type |
string | Filter: income | expense |
category_id |
uuid | Filter by category |
user_id |
uuid | Filter by family member |
date_from |
datetime | Start date (ISO 8601) |
date_to |
datetime | End date (ISO 8601) |
min_amount |
decimal | Minimum transaction amount |
max_amount |
decimal | Maximum transaction amount |
search |
string | Full-text search on description |
Response 200:
{
"items": [...],
"total": 248,
"page": 1,
"page_size": 20,
"total_pages": 13
}Get a single transaction.
Update a transaction (partial update).
Soft-delete a transaction. Response: 204 No Content
Query Parameters: year (int), month (int, 1-12)
Response 200:
{
"total_income": "12450.00",
"total_expenses": "8200.00",
"net_savings": "4250.00",
"savings_rate": 34.1,
"income_change_pct": 12.5,
"expense_change_pct": 4.2,
"monthly_trends": [
{
"month": "2024-10",
"income": "12450.00",
"expenses": "8200.00",
"net": "4250.00",
"savings_rate": 34.1
}
],
"category_breakdown": [
{
"category_id": "uuid",
"category_name": "Housing",
"total": "3700.00",
"percentage": 45.1,
"transaction_count": 3
}
],
"financial_health_score": 78.5
}Response 200:
{
"score": 78.5,
"grade": "Good",
"savings_rate_score": 28.0,
"debt_to_income_score": 22.5,
"liquidity_score": 18.0,
"trend_score": 10.0,
"recommendations": [
"Consider building a 6-month emergency fund.",
"Your dining spend is 18% above your 3-month average."
]
}Grades: Excellent (80+) | Good (60-79) | Fair (40-59) | Poor (<40)
Query Parameters: periods (int, 1-12, default: 3)
Response 200:
[
{
"month": "2024-11",
"predicted_expenses": "8450.00",
"confidence_interval_low": "7200.00",
"confidence_interval_high": "9700.00",
"model_used": "linear_regression"
}
]Response 200:
[
{
"transaction_id": "tx-uuid",
"description": "Selfridges & Co.",
"amount": "4200.00",
"anomaly_score": 0.847,
"reason": "Amount is 3.2 standard deviations above your average spend."
}
]Request Body:
{
"message": "Am I on track for my house fund goal?",
"history": [
{ "role": "user", "content": "Hello" },
{ "role": "assistant", "content": "Good morning! How can I help?" }
]
}Response 200:
{
"reply": "Based on your current savings rate of 34% and the $450,000 already saved toward your $700,000 House Fund goal, you are on track. At your current pace of ~$4,250/month, you'll reach your target in approximately 14 months..."
}Request Body:
{ "year": 2024, "month": 10 }Response 200:
{
"summary": "October 2024 was a strong month for the Sterling family...",
"year": 2024,
"month": 10
}Response 200:
[
{
"type": "overspend_alert",
"severity": "medium",
"title": "High Food & Dining Spend",
"body": "Food & Dining accounts for 28% of your expenses this month ($2,300).",
"action": "Set a Food & Dining budget limit to stay on track."
}
]Response 200:
{
"recommendations": [
"Redirect the $420 monthly surplus to your House Fund escrow account.",
"Consider switching to annual billing on streaming subscriptions to save ~$180/year.",
"Your utility spend is 15% above comparable households – consider an energy audit."
]
}Create a savings goal.
Request Body:
{
"name": "House Fund",
"description": "Pacific Heights Estate Acquisition",
"icon": "🏠",
"target_amount": 700000.00,
"target_date": "2025-12-31",
"priority": "high"
}Priorities: low | medium | high
List all savings goals.
Update a goal.
Request Body:
{ "amount": 1250.00 }Soft-delete a goal. Response: 204 No Content
Query Parameters: year (int), month (int)
Upsert (create or update) a budget for a category/month. Requires can_manage_budgets permission.
Request Body:
{
"category_id": "cat-uuid",
"month": 10,
"year": 2024,
"limit_amount": 3200.00
}Upload a receipt image for OCR extraction.
Request: multipart/form-data with file field.
Accepted types: image/jpeg, image/png, image/webp, application/pdf
Max size: 10 MB
Response 201:
{
"file_id": "file-uuid",
"ocr_extracted": {
"merchant_name": "Whole Foods Market",
"total_amount": "245.50",
"date": "10/24/2024",
"suggested_category": "Grocery",
"confidence": 0.87
}
}Download a monthly report as PDF.
Query Parameters: year (int), month (int)
Response: application/pdf binary stream with Content-Disposition: attachment
Export transactions as Excel workbook.
Query Parameters: date_from (datetime), date_to (datetime)
Response: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Query Parameters: unread_only (bool), limit (int, max 200)
Response 200:
[
{
"id": "notif-uuid",
"type": "budget_alert",
"title": "Budget Alert – Food & Dining",
"body": "You've used 92% of your Food & Dining budget.",
"action_url": "/budget",
"is_read": false,
"created_at": "2024-10-24T09:00:00Z"
}
]Notification types: budget_alert | bill_reminder | goal_milestone | ai_insight | anomaly_detected | system
{ "notification_ids": ["uuid1", "uuid2"] }Marks all unread notifications as read.
| Code | Meaning |
|---|---|
| 200 | OK – request succeeded |
| 201 | Created – resource created successfully |
| 204 | No Content – deletion or action succeeded |
| 400 | Bad Request – invalid input |
| 401 | Unauthorized – missing or invalid token |
| 403 | Forbidden – insufficient permissions |
| 404 | Not Found – resource does not exist |
| 409 | Conflict – duplicate or constraint violation |
| 413 | Payload Too Large – file exceeds size limit |
| 415 | Unsupported Media Type – invalid file type |
| 422 | Unprocessable Entity – schema validation fail |
| 429 | Too Many Requests – rate limit exceeded |
| 500 | Internal Server Error – unexpected failure |