Skip to content

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.

Authorization: Bearer <your_token>

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.