Account API
This document provides information about the Account API endpoints in the UBU Finance backend.
Overview
The Account API allows you to create, retrieve, update, and manage financial accounts within the UBU Finance system. Accounts represent containers for funds and are associated with users or organizations.
Authentication
All Account API endpoints require authentication. You must include a valid JWT token in the Authorization header of your requests.
Endpoints
List Accounts
Retrieves a list of accounts with optional filtering.
Endpoint: GET /api/accounts
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
| page | integer | Page number for pagination (default: 1) |
| limit | integer | Number of items per page (default: 10, max: 100) |
| account_id | UUID | Filter by account ID |
| account_number | string | Filter by account number |
| customer_id | UUID | Filter by customer ID |
| account_type_id | UUID | Filter by account type ID |
| status | string | Filter by account status (e.g., 'active', 'inactive', 'closed') |
| currency | string | Filter by currency code (e.g., 'RWF', 'EUR') |
| min_balance | decimal | Filter accounts with balance greater than or equal to this value |
| max_balance | decimal | Filter accounts with balance less than or equal to this value |
| created_after | datetime | Filter accounts created after this date and time (ISO 8601 format) |
| created_before | datetime | Filter accounts created before this date and time (ISO 8601 format) |
Response:
{
"items": [
{
"account_id": "550e8400-e29b-41d4-a716-446655440001",
"account_number": "ACC-12345",
"account_type": "savings",
"user_id": "550e8400-e29b-41d4-a716-446655440010",
"organization_id": null,
"balance": 5000.00,
"available_balance": 5000.00,
"currency": "RWF",
"status": "active",
"created_at": "2025-01-01T12:00:00Z",
"updated_at": "2025-01-01T12:00:00Z"
}
],
"total": 1,
"page": 1,
"limit": 10,
"pages": 1
}
Get Account
Retrieves details of a specific account.
Endpoint: GET /api/accounts/{account_id}
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
| account_id | UUID | The ID of the account to retrieve |
Response:
{
"account_id": "550e8400-e29b-41d4-a716-446655440001",
"account_number": "ACC-12345",
"account_type": "savings",
"user_id": "550e8400-e29b-41d4-a716-446655440010",
"organization_id": null,
"balance": 5000.00,
"available_balance": 5000.00,
"currency": "RWF",
"status": "active",
"interest_rate": 2.5,
"overdraft_limit": 0.00,
"created_at": "2025-01-01T12:00:00Z",
"updated_at": "2025-01-01T12:00:00Z",
"metadata": {
"branch_code": "BR-001",
"account_manager": "John Doe"
}
}
Create Account
Creates a new account.
Endpoint: POST /api/accounts
Request Body:
{
"account_type": "checking",
"user_id": "550e8400-e29b-41d4-a716-446655440010",
"currency": "RWF",
"initial_deposit": 1000.00,
"metadata": {
"branch_code": "BR-001",
"purpose": "daily expenses"
}
}
Response:
{
"account_id": "550e8400-e29b-41d4-a716-446655440002",
"account_number": "ACC-12346",
"account_type": "checking",
"user_id": "550e8400-e29b-41d4-a716-446655440010",
"organization_id": null,
"balance": 1000.00,
"available_balance": 1000.00,
"currency": "RWF",
"status": "active",
"created_at": "2025-01-02T12:00:00Z",
"updated_at": "2025-01-02T12:00:00Z",
"metadata": {
"branch_code": "BR-001",
"purpose": "daily expenses"
}
}
Update Account
Updates an existing account.
Endpoint: PUT /api/accounts/{account_id}
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
| account_id | UUID | The ID of the account to update |
Request Body:
Response:
{
"account_id": "550e8400-e29b-41d4-a716-446655440002",
"account_number": "ACC-12346",
"account_type": "checking",
"user_id": "550e8400-e29b-41d4-a716-446655440010",
"organization_id": null,
"balance": 1000.00,
"available_balance": 1000.00,
"currency": "RWF",
"status": "inactive",
"created_at": "2025-01-02T12:00:00Z",
"updated_at": "2025-01-02T12:15:00Z",
"metadata": {
"branch_code": "BR-002",
"purpose": "savings"
}
}
Close Account
Closes an account. The account must have a zero balance.
Endpoint: DELETE /api/accounts/{account_id}
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
| account_id | UUID | The ID of the account to close |
Response:
{
"account_id": "550e8400-e29b-41d4-a716-446655440002",
"status": "closed",
"closed_at": "2025-01-02T12:30:00Z"
}
Get Account Transactions
Retrieves transactions for a specific account.
Endpoint: GET /api/accounts/{account_id}/transactions
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
| account_id | UUID | The ID of the account |
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
| page | integer | Page number for pagination (default: 1) |
| limit | integer | Number of items per page (default: 10, max: 100) |
| start_date | date | Filter transactions after this date (format: YYYY-MM-DD) |
| end_date | date | Filter transactions before this date (format: YYYY-MM-DD) |
| transaction_type | string | Filter by transaction type (e.g., 'deposit', 'withdrawal', 'transfer') |
Response:
{
"items": [
{
"transaction_id": "550e8400-e29b-41d4-a716-446655440003",
"transaction_type": "deposit",
"amount": 1000.00,
"currency": "RWF",
"source_account_id": null,
"destination_account_id": "550e8400-e29b-41d4-a716-446655440001",
"status": "completed",
"description": "Initial deposit",
"created_at": "2025-01-01T12:00:00Z"
}
],
"total": 1,
"page": 1,
"limit": 10,
"pages": 1
}
Get Account Statement
Generates a statement for a specific account for a given period.
Endpoint: GET /api/accounts/{account_id}/statement
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
| account_id | UUID | The ID of the account |
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
| start_date | date | Start date for the statement (format: YYYY-MM-DD) |
| end_date | date | End date for the statement (format: YYYY-MM-DD) |
| format | string | Statement format (options: 'json', 'pdf', 'csv', default: 'json') |
Response:
For JSON format:
{
"account_id": "550e8400-e29b-41d4-a716-446655440001",
"account_number": "ACC-12345",
"account_type": "savings",
"user_id": "550e8400-e29b-41d4-a716-446655440010",
"statement_period": {
"start_date": "2025-01-01",
"end_date": "2025-01-31"
},
"opening_balance": 5000.00,
"closing_balance": 5500.00,
"total_deposits": 1000.00,
"total_withdrawals": 500.00,
"transactions": [
{
"transaction_id": "550e8400-e29b-41d4-a716-446655440003",
"date": "2025-01-05T12:00:00Z",
"description": "Salary deposit",
"amount": 1000.00,
"balance_after": 6000.00
},
{
"transaction_id": "550e8400-e29b-41d4-a716-446655440004",
"date": "2025-01-15T12:00:00Z",
"description": "Rent payment",
"amount": -500.00,
"balance_after": 5500.00
}
]
}
For PDF and CSV formats, the response will be a file download.
Client Implementation Examples
Python
import requests
import json
# Configuration
API_URL = "http://localhost:8080"
TOKEN = "your_jwt_token"
headers = {
"Authorization": f"Bearer {TOKEN}",
"Content-Type": "application/json"
}
# List accounts
def list_accounts(user_id=None, account_type=None, page=1, limit=10):
params = {
"page": page,
"limit": limit
}
if user_id:
params["user_id"] = user_id
if account_type:
params["account_type"] = account_type
response = requests.get(f"{API_URL}/api/accounts", headers=headers, params=params)
if response.status_code == 200:
return response.json()
else:
print(f"Error: {response.status_code}")
print(response.text)
return None
# Create an account
def create_account(account_type, user_id, currency, initial_deposit=0):
payload = {
"account_type": account_type,
"user_id": user_id,
"currency": currency,
"initial_deposit": initial_deposit
}
response = requests.post(f"{API_URL}/api/accounts", headers=headers, json=payload)
if response.status_code == 201:
return response.json()
else:
print(f"Error: {response.status_code}")
print(response.text)
return None
# Get account statement
def get_account_statement(account_id, start_date, end_date, format="json"):
params = {
"start_date": start_date,
"end_date": end_date,
"format": format
}
response = requests.get(f"{API_URL}/api/accounts/{account_id}/statement", headers=headers, params=params)
if response.status_code == 200:
if format == "json":
return response.json()
else:
# Handle file download
return response.content
else:
print(f"Error: {response.status_code}")
print(response.text)
return None
# Example usage
accounts = list_accounts(user_id="550e8400-e29b-41d4-a716-446655440010")
print(json.dumps(accounts, indent=2))
new_account = create_account(
account_type="savings",
user_id="550e8400-e29b-41d4-a716-446655440010",
currency="RWF",
initial_deposit=1000.00
)
print(json.dumps(new_account, indent=2))
statement = get_account_statement(
account_id="550e8400-e29b-41d4-a716-446655440001",
start_date="2025-01-01",
end_date="2025-01-31"
)
print(json.dumps(statement, indent=2))
JavaScript
// Configuration
const API_URL = 'http://localhost:8080';
const TOKEN = 'your_jwt_token';
const headers = {
'Authorization': `Bearer ${TOKEN}`,
'Content-Type': 'application/json'
};
// List accounts
async function listAccounts(params = {}) {
const queryParams = new URLSearchParams();
for (const [key, value] of Object.entries(params)) {
if (value !== undefined && value !== null) {
queryParams.append(key, value);
}
}
const url = `${API_URL}/api/accounts?${queryParams.toString()}`;
try {
const response = await fetch(url, {
method: 'GET',
headers
});
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Error listing accounts:', error);
throw error;
}
}
// Create an account
async function createAccount(accountData) {
try {
const response = await fetch(`${API_URL}/api/accounts`, {
method: 'POST',
headers,
body: JSON.stringify(accountData)
});
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Error creating account:', error);
throw error;
}
}
// Get account statement
async function getAccountStatement(accountId, startDate, endDate, format = 'json') {
const queryParams = new URLSearchParams({
start_date: startDate,
end_date: endDate,
format
});
const url = `${API_URL}/api/accounts/${accountId}/statement?${queryParams.toString()}`;
try {
const response = await fetch(url, {
method: 'GET',
headers
});
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
if (format === 'json') {
return await response.json();
} else {
// Handle file download
return await response.blob();
}
} catch (error) {
console.error('Error getting account statement:', error);
throw error;
}
}
// Example usage
async function exampleUsage() {
try {
// List accounts for a specific user
const accounts = await listAccounts({
user_id: '550e8400-e29b-41d4-a716-446655440010',
page: 1,
limit: 10
});
console.log('Accounts:', accounts);
// Create a new account
const newAccount = await createAccount({
account_type: 'savings',
user_id: '550e8400-e29b-41d4-a716-446655440010',
currency: 'RWF',
initial_deposit: 1000.00
});
console.log('New account:', newAccount);
// Get account statement
const statement = await getAccountStatement(
'550e8400-e29b-41d4-a716-446655440001',
'2025-01-01',
'2025-01-31'
);
console.log('Statement:', statement);
} catch (error) {
console.error('Example usage error:', error);
}
}
exampleUsage();
cURL
# Set your JWT token
TOKEN="your_jwt_token"
# List accounts
curl -X GET "http://localhost:8080/api/accounts?page=1&limit=10" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json"
# Get a specific account
curl -X GET "http://localhost:8080/api/accounts/550e8400-e29b-41d4-a716-446655440001" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json"
# Create an account
curl -X POST "http://localhost:8080/api/accounts" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"account_type": "savings",
"user_id": "550e8400-e29b-41d4-a716-446655440010",
"currency": "RWF",
"initial_deposit": 1000.00
}'
# Update an account
curl -X PUT "http://localhost:8080/api/accounts/550e8400-e29b-41d4-a716-446655440001" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"status": "inactive"
}'
# Get account transactions
curl -X GET "http://localhost:8080/api/accounts/550e8400-e29b-41d4-a716-446655440001/transactions" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json"
# Get account statement
curl -X GET "http://localhost:8080/api/accounts/550e8400-e29b-41d4-a716-446655440001/statement?start_date=2025-01-01&end_date=2025-01-31&format=json" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json"
C
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
namespace UbuFinanceClient
{
class Program
{
private static readonly HttpClient client = new HttpClient();
private static readonly string ApiUrl = "http://localhost:8080";
private static readonly string Token = "your_jwt_token";
static async Task Main(string[] args)
{
// Configure HttpClient
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Token);
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// List accounts
await ListAccountsAsync();
// Create an account
await CreateAccountAsync();
// Get account statement
await GetAccountStatementAsync();
}
static async Task ListAccountsAsync()
{
try
{
HttpResponseMessage response = await client.GetAsync($"{ApiUrl}/api/accounts?page=1&limit=10");
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("Accounts:");
Console.WriteLine(responseBody);
}
catch (HttpRequestException e)
{
Console.WriteLine($"Error listing accounts: {e.Message}");
}
}
static async Task CreateAccountAsync()
{
var account = new
{
account_type = "savings",
user_id = "550e8400-e29b-41d4-a716-446655440010",
currency = "RWF",
initial_deposit = 1000.00
};
var json = JsonSerializer.Serialize(account);
var content = new StringContent(json, Encoding.UTF8, "application/json");
try
{
HttpResponseMessage response = await client.PostAsync($"{ApiUrl}/api/accounts", content);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("New Account:");
Console.WriteLine(responseBody);
}
catch (HttpRequestException e)
{
Console.WriteLine($"Error creating account: {e.Message}");
}
}
static async Task GetAccountStatementAsync()
{
string accountId = "550e8400-e29b-41d4-a716-446655440001";
string startDate = "2025-01-01";
string endDate = "2025-01-31";
try
{
HttpResponseMessage response = await client.GetAsync(
$"{ApiUrl}/api/accounts/{accountId}/statement?start_date={startDate}&end_date={endDate}&format=json");
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("Account Statement:");
Console.WriteLine(responseBody);
}
catch (HttpRequestException e)
{
Console.WriteLine($"Error getting account statement: {e.Message}");
}
}
}
}
Error Handling
The Account API returns standard HTTP status codes:
| Status Code | Description |
|---|---|
| 200 | OK - The request was successful |
| 201 | Created - A new resource was created |
| 400 | Bad Request - The request was invalid |
| 401 | Unauthorized - Authentication is required |
| 403 | Forbidden - The user does not have permission |
| 404 | Not Found - The resource was not found |
| 409 | Conflict - The request could not be completed due to a conflict |
| 422 | Unprocessable Entity - The request was well-formed but could not be processed |
| 500 | Internal Server Error - An error occurred on the server |
Error responses include a JSON body with details:
{
"error": {
"code": "account_not_empty",
"message": "Cannot close account with non-zero balance",
"details": {
"account_id": "550e8400-e29b-41d4-a716-446655440001",
"current_balance": 500.00
}
}
}
Rate Limiting
The Account API is subject to rate limiting. See the Rate Limiting documentation for details.
Security Considerations
- All Account API endpoints are protected by authentication
- Sensitive operations require appropriate permissions
- All requests are logged for audit purposes
- Account creation and closure operations are subject to additional verification
- IP whitelisting may be enforced for sensitive operations
For more information on security features, see the Security Overview.