Payment API
This document provides information about the Payment API endpoints in the UBU Finance backend.
Overview
The Payment API allows you to process, track, and manage payments within the UBU Finance system. This includes one-time payments, recurring payments, and payment processing for various services.
Authentication
All Payment API endpoints require authentication. You must include a valid JWT token in the Authorization header of your requests.
Endpoints
List Payments
Retrieves a list of payments with optional filtering.
Endpoint: GET /api/payments
Query Parameters:
| Parameter | Type | Description |
|---|---|---|
| page | integer | Page number for pagination (default: 1) |
| limit | integer | Number of items per page (default: 10, max: 100) |
| payment_id | UUID | Filter by payment ID |
| payer_id | UUID | Filter by payer ID |
| payee_id | UUID | Filter by payee ID |
| source_account_id | UUID | Filter by source account ID |
| destination_account_id | UUID | Filter by destination account ID |
| payment_method_id | UUID | Filter by payment method ID |
| status | string | Filter by payment status (e.g., 'pending', 'completed', 'failed') |
| min_amount | decimal | Filter payments with amount greater than or equal to this value |
| max_amount | decimal | Filter payments with amount less than or equal to this value |
| currency | string | Filter by currency code (e.g., 'RWF', 'EUR') |
| created_after | datetime | Filter payments created after this date and time (ISO 8601 format) |
| created_before | datetime | Filter payments created before this date and time (ISO 8601 format) |
| completed_after | datetime | Filter payments completed after this date and time (ISO 8601 format) |
| completed_before | datetime | Filter payments completed before this date and time (ISO 8601 format) |
Response:
{
"items": [
{
"payment_id": "550e8400-e29b-41d4-a716-446655440001",
"reference_number": "PAY-12345",
"user_id": "550e8400-e29b-41d4-a716-446655440010",
"payment_type": "one-time",
"amount": 500.00,
"currency": "RWF",
"status": "completed",
"payment_method": "bank_transfer",
"source_account_id": "550e8400-e29b-41d4-a716-446655440002",
"destination_account_id": "550e8400-e29b-41d4-a716-446655440003",
"payment_date": "2025-01-15T12:00:00Z",
"created_at": "2025-01-15T12:00:00Z",
"updated_at": "2025-01-15T12:05:00Z"
}
],
"total": 1,
"page": 1,
"limit": 10,
"pages": 1
}
Get Payment
Retrieves details of a specific payment.
Endpoint: GET /api/payments/{payment_id}
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
| payment_id | UUID | The ID of the payment to retrieve |
Response:
{
"payment_id": "550e8400-e29b-41d4-a716-446655440001",
"reference_number": "PAY-12345",
"user_id": "550e8400-e29b-41d4-a716-446655440010",
"payment_type": "one-time",
"amount": 500.00,
"currency": "RWF",
"status": "completed",
"payment_method": "bank_transfer",
"source_account_id": "550e8400-e29b-41d4-a716-446655440002",
"destination_account_id": "550e8400-e29b-41d4-a716-446655440003",
"payment_date": "2025-01-15T12:00:00Z",
"transaction_id": "550e8400-e29b-41d4-a716-446655440020",
"description": "Rent payment",
"metadata": {
"category": "housing",
"recipient_name": "ABC Properties"
},
"created_at": "2025-01-15T12:00:00Z",
"updated_at": "2025-01-15T12:05:00Z"
}
Create Payment
Creates a new payment.
Endpoint: POST /api/payments
Request Body:
{
"user_id": "550e8400-e29b-41d4-a716-446655440010",
"payment_type": "one-time",
"amount": 500.00,
"currency": "RWF",
"payment_method": "bank_transfer",
"source_account_id": "550e8400-e29b-41d4-a716-446655440002",
"destination_account_id": "550e8400-e29b-41d4-a716-446655440003",
"description": "Rent payment",
"metadata": {
"category": "housing",
"recipient_name": "ABC Properties"
}
}
Response:
{
"payment_id": "550e8400-e29b-41d4-a716-446655440001",
"reference_number": "PAY-12345",
"user_id": "550e8400-e29b-41d4-a716-446655440010",
"payment_type": "one-time",
"amount": 500.00,
"currency": "RWF",
"status": "pending",
"payment_method": "bank_transfer",
"source_account_id": "550e8400-e29b-41d4-a716-446655440002",
"destination_account_id": "550e8400-e29b-41d4-a716-446655440003",
"payment_date": "2025-01-15T12:00:00Z",
"description": "Rent payment",
"metadata": {
"category": "housing",
"recipient_name": "ABC Properties"
},
"created_at": "2025-01-15T12:00:00Z",
"updated_at": "2025-01-15T12:00:00Z"
}
Create Recurring Payment
Sets up a recurring payment.
Endpoint: POST /api/payments/recurring
Request Body:
{
"user_id": "550e8400-e29b-41d4-a716-446655440010",
"amount": 500.00,
"currency": "RWF",
"payment_method": "bank_transfer",
"source_account_id": "550e8400-e29b-41d4-a716-446655440002",
"destination_account_id": "550e8400-e29b-41d4-a716-446655440003",
"description": "Monthly rent payment",
"frequency": "monthly",
"start_date": "2025-02-01",
"end_date": "2025-12-31",
"metadata": {
"category": "housing",
"recipient_name": "ABC Properties"
}
}
Response:
{
"recurring_payment_id": "550e8400-e29b-41d4-a716-446655440005",
"reference_number": "REC-12345",
"user_id": "550e8400-e29b-41d4-a716-446655440010",
"amount": 500.00,
"currency": "RWF",
"payment_method": "bank_transfer",
"source_account_id": "550e8400-e29b-41d4-a716-446655440002",
"destination_account_id": "550e8400-e29b-41d4-a716-446655440003",
"description": "Monthly rent payment",
"frequency": "monthly",
"start_date": "2025-02-01",
"end_date": "2025-12-31",
"status": "active",
"next_payment_date": "2025-02-01",
"metadata": {
"category": "housing",
"recipient_name": "ABC Properties"
},
"created_at": "2025-01-15T12:00:00Z",
"updated_at": "2025-01-15T12:00:00Z"
}
Cancel Payment
Cancels a pending payment.
Endpoint: DELETE /api/payments/{payment_id}
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
| payment_id | UUID | The ID of the payment to cancel |
Response:
{
"payment_id": "550e8400-e29b-41d4-a716-446655440001",
"status": "cancelled",
"updated_at": "2025-01-15T12:10:00Z"
}
Cancel Recurring Payment
Cancels a recurring payment.
Endpoint: DELETE /api/payments/recurring/{recurring_payment_id}
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
| recurring_payment_id | UUID | The ID of the recurring payment to cancel |
Response:
{
"recurring_payment_id": "550e8400-e29b-41d4-a716-446655440005",
"status": "cancelled",
"updated_at": "2025-01-15T12:10:00Z"
}
Get Payment History
Retrieves the history of status changes for a payment.
Endpoint: GET /api/payments/{payment_id}/history
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
| payment_id | UUID | The ID of the payment |
Response:
{
"payment_id": "550e8400-e29b-41d4-a716-446655440001",
"history": [
{
"status": "pending",
"timestamp": "2025-01-15T12:00:00Z",
"user_id": "550e8400-e29b-41d4-a716-446655440010"
},
{
"status": "processing",
"timestamp": "2025-01-15T12:02:00Z",
"user_id": null
},
{
"status": "completed",
"timestamp": "2025-01-15T12:05:00Z",
"user_id": null
}
]
}
Get Recurring Payment Schedule
Retrieves the schedule for a recurring payment.
Endpoint: GET /api/payments/recurring/{recurring_payment_id}/schedule
Path Parameters:
| Parameter | Type | Description |
|---|---|---|
| recurring_payment_id | UUID | The ID of the recurring payment |
Response:
{
"recurring_payment_id": "550e8400-e29b-41d4-a716-446655440005",
"reference_number": "REC-12345",
"frequency": "monthly",
"total_payments": 11,
"completed_payments": 1,
"remaining_payments": 10,
"schedule": [
{
"payment_number": 1,
"scheduled_date": "2025-02-01",
"payment_id": "550e8400-e29b-41d4-a716-446655440006",
"status": "completed",
"amount": 500.00
},
{
"payment_number": 2,
"scheduled_date": "2025-03-01",
"payment_id": null,
"status": "scheduled",
"amount": 500.00
}
]
}
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 payments
def list_payments(user_id=None, payment_type=None, page=1, limit=10):
params = {
"page": page,
"limit": limit
}
if user_id:
params["user_id"] = user_id
if payment_type:
params["payment_type"] = payment_type
response = requests.get(f"{API_URL}/api/payments", 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 a payment
def create_payment(user_id, amount, currency, payment_method, source_account_id, destination_account_id, description):
payload = {
"user_id": user_id,
"payment_type": "one-time",
"amount": amount,
"currency": currency,
"payment_method": payment_method,
"source_account_id": source_account_id,
"destination_account_id": destination_account_id,
"description": description
}
response = requests.post(f"{API_URL}/api/payments", headers=headers, json=payload)
if response.status_code == 201:
return response.json()
else:
print(f"Error: {response.status_code}")
print(response.text)
return None
# Create a recurring payment
def create_recurring_payment(user_id, amount, currency, payment_method, source_account_id,
destination_account_id, description, frequency, start_date, end_date=None):
payload = {
"user_id": user_id,
"amount": amount,
"currency": currency,
"payment_method": payment_method,
"source_account_id": source_account_id,
"destination_account_id": destination_account_id,
"description": description,
"frequency": frequency,
"start_date": start_date
}
if end_date:
payload["end_date"] = end_date
response = requests.post(f"{API_URL}/api/payments/recurring", headers=headers, json=payload)
if response.status_code == 201:
return response.json()
else:
print(f"Error: {response.status_code}")
print(response.text)
return None
# Example usage
payments = list_payments(user_id="550e8400-e29b-41d4-a716-446655440010")
print(json.dumps(payments, indent=2))
new_payment = create_payment(
user_id="550e8400-e29b-41d4-a716-446655440010",
amount=500.00,
currency="RWF",
payment_method="bank_transfer",
source_account_id="550e8400-e29b-41d4-a716-446655440002",
destination_account_id="550e8400-e29b-41d4-a716-446655440003",
description="Rent payment"
)
print(json.dumps(new_payment, indent=2))
recurring_payment = create_recurring_payment(
user_id="550e8400-e29b-41d4-a716-446655440010",
amount=500.00,
currency="RWF",
payment_method="bank_transfer",
source_account_id="550e8400-e29b-41d4-a716-446655440002",
destination_account_id="550e8400-e29b-41d4-a716-446655440003",
description="Monthly rent payment",
frequency="monthly",
start_date="2025-02-01",
end_date="2025-12-31"
)
print(json.dumps(recurring_payment, 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 payments
async function listPayments(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/payments?${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 payments:', error);
throw error;
}
}
// Create a payment
async function createPayment(paymentData) {
try {
const response = await fetch(`${API_URL}/api/payments`, {
method: 'POST',
headers,
body: JSON.stringify(paymentData)
});
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Error creating payment:', error);
throw error;
}
}
// Create a recurring payment
async function createRecurringPayment(recurringPaymentData) {
try {
const response = await fetch(`${API_URL}/api/payments/recurring`, {
method: 'POST',
headers,
body: JSON.stringify(recurringPaymentData)
});
if (!response.ok) {
throw new Error(`HTTP error! Status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Error creating recurring payment:', error);
throw error;
}
}
// Example usage
async function exampleUsage() {
try {
// List payments for a specific user
const payments = await listPayments({
user_id: '550e8400-e29b-41d4-a716-446655440010',
payment_type: 'one-time',
page: 1,
limit: 10
});
console.log('Payments:', payments);
// Create a new payment
const newPayment = await createPayment({
user_id: '550e8400-e29b-41d4-a716-446655440010',
payment_type: 'one-time',
amount: 500.00,
currency: 'RWF',
payment_method: 'bank_transfer',
source_account_id: '550e8400-e29b-41d4-a716-446655440002',
destination_account_id: '550e8400-e29b-41d4-a716-446655440003',
description: 'Rent payment'
});
console.log('New payment:', newPayment);
// Create a recurring payment
const recurringPayment = await createRecurringPayment({
user_id: '550e8400-e29b-41d4-a716-446655440010',
amount: 500.00,
currency: 'RWF',
payment_method: 'bank_transfer',
source_account_id: '550e8400-e29b-41d4-a716-446655440002',
destination_account_id: '550e8400-e29b-41d4-a716-446655440003',
description: 'Monthly rent payment',
frequency: 'monthly',
start_date: '2025-02-01',
end_date: '2025-12-31'
});
console.log('Recurring payment:', recurringPayment);
} catch (error) {
console.error('Example usage error:', error);
}
}
exampleUsage();
cURL
# Set your JWT token
TOKEN="your_jwt_token"
# List payments
curl -X GET "http://localhost:8080/api/payments?page=1&limit=10" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json"
# Get a specific payment
curl -X GET "http://localhost:8080/api/payments/550e8400-e29b-41d4-a716-446655440001" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json"
# Create a payment
curl -X POST "http://localhost:8080/api/payments" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"user_id": "550e8400-e29b-41d4-a716-446655440010",
"payment_type": "one-time",
"amount": 500.00,
"currency": "RWF",
"payment_method": "bank_transfer",
"source_account_id": "550e8400-e29b-41d4-a716-446655440002",
"destination_account_id": "550e8400-e29b-41d4-a716-446655440003",
"description": "Rent payment"
}'
# Create a recurring payment
curl -X POST "http://localhost:8080/api/payments/recurring" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"user_id": "550e8400-e29b-41d4-a716-446655440010",
"amount": 500.00,
"currency": "RWF",
"payment_method": "bank_transfer",
"source_account_id": "550e8400-e29b-41d4-a716-446655440002",
"destination_account_id": "550e8400-e29b-41d4-a716-446655440003",
"description": "Monthly rent payment",
"frequency": "monthly",
"start_date": "2025-02-01",
"end_date": "2025-12-31"
}'
# Cancel a payment
curl -X DELETE "http://localhost:8080/api/payments/550e8400-e29b-41d4-a716-446655440001" \
-H "Authorization: Bearer $TOKEN"
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 payments
await ListPaymentsAsync();
// Create a payment
await CreatePaymentAsync();
// Create a recurring payment
await CreateRecurringPaymentAsync();
}
static async Task ListPaymentsAsync()
{
try
{
HttpResponseMessage response = await client.GetAsync($"{ApiUrl}/api/payments?page=1&limit=10");
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("Payments:");
Console.WriteLine(responseBody);
}
catch (HttpRequestException e)
{
Console.WriteLine($"Error listing payments: {e.Message}");
}
}
static async Task CreatePaymentAsync()
{
var payment = new
{
user_id = "550e8400-e29b-41d4-a716-446655440010",
payment_type = "one-time",
amount = 500.00,
currency = "RWF",
payment_method = "bank_transfer",
source_account_id = "550e8400-e29b-41d4-a716-446655440002",
destination_account_id = "550e8400-e29b-41d4-a716-446655440003",
description = "Rent payment"
};
var json = JsonSerializer.Serialize(payment);
var content = new StringContent(json, Encoding.UTF8, "application/json");
try
{
HttpResponseMessage response = await client.PostAsync($"{ApiUrl}/api/payments", content);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("New Payment:");
Console.WriteLine(responseBody);
}
catch (HttpRequestException e)
{
Console.WriteLine($"Error creating payment: {e.Message}");
}
}
static async Task CreateRecurringPaymentAsync()
{
var recurringPayment = new
{
user_id = "550e8400-e29b-41d4-a716-446655440010",
amount = 500.00,
currency = "RWF",
payment_method = "bank_transfer",
source_account_id = "550e8400-e29b-41d4-a716-446655440002",
destination_account_id = "550e8400-e29b-41d4-a716-446655440003",
description = "Monthly rent payment",
frequency = "monthly",
start_date = "2025-02-01",
end_date = "2025-12-31"
};
var json = JsonSerializer.Serialize(recurringPayment);
var content = new StringContent(json, Encoding.UTF8, "application/json");
try
{
HttpResponseMessage response = await client.PostAsync($"{ApiUrl}/api/payments/recurring", content);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Console.WriteLine("New Recurring Payment:");
Console.WriteLine(responseBody);
}
catch (HttpRequestException e)
{
Console.WriteLine($"Error creating recurring payment: {e.Message}");
}
}
}
}
Error Handling
The Payment 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": "insufficient_funds",
"message": "Insufficient funds in source account",
"details": {
"account_id": "550e8400-e29b-41d4-a716-446655440002",
"available_balance": 400.00,
"required_amount": 500.00
}
}
}
Rate Limiting
The Payment API is subject to rate limiting. See the Rate Limiting documentation for details.
Security Considerations
- All Payment API endpoints are protected by authentication
- Sensitive operations require appropriate permissions
- All requests are logged for audit purposes
- Payment processing is subject to additional verification
- IP whitelisting may be enforced for payment operations
- Account lockout is triggered after multiple failed payment attempts
For more information on security features, see the Security Overview.