Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.digiflecttech.dev/llms.txt

Use this file to discover all available pages before exploring further.

The Save App loan system lets members request funds against their accumulated savings and gives admins the tools to review and act on those requests. Members can list their own loans and submit new requests, while admins see all loans across the group and can approve or reject pending ones.

Loan statuses

A loan moves through the following statuses during its lifecycle:
StatusMeaning
PENDINGSubmitted and awaiting admin approval
APPROVEDAll admins have approved; funds can be disbursed
ACTIVELoan is currently being repaid
COMPLETEDFully repaid
REJECTEDDeclined by an admin
OVERDUEActive loan that has passed its due date

List loans

Retrieve a paginated list of loans. Members only see their own loans; admins see all loans in the group. Filter by status using the status query parameter.
GET /api/loans

Query parameters

status
string
Filter loans by status. Accepted values: pending, approved, active, completed, rejected, overdue.
limit
number
default:"20"
Number of loans to return per page. Minimum 1, maximum 100.
offset
number
default:"0"
Number of loans to skip before returning results. Use with limit for pagination.

Response fields

data
object[]
Array of loan objects matching the query.
total
number
required
Total number of loans matching the query, before pagination.
limit
number
required
The limit value applied to this response.
offset
number
required
The offset value applied to this response.

Example

curl --request GET \
  --url 'https://api.saveapp.example.com/api/loans?limit=20&offset=0' \
  --header 'Authorization: Bearer <token>'

Submit a loan request

Submit a new loan request on behalf of a member. The requesting member must not have an existing active or pending loan, and the amount must not exceed their eligibility (3× total contributions).
POST /api/loans

Request body

memberName
string
required
Full name of the member requesting the loan. Must match an existing member record. Minimum 2 characters, maximum 100 characters.
amount
number
required
Loan principal in the group’s currency. Must be greater than 0 and must not exceed the member’s maximum eligibility (3× their total contributions).
durationMonths
number
required
Repayment duration in months. Minimum 1, maximum 24.
reason
string
required
Purpose of the loan. Minimum 2 characters, maximum 200 characters.
guarantor
string
Full name of the guarantor. Minimum 2 characters, maximum 100 characters.
guarantorPhone
string
Ugandan phone number for the guarantor. Must match the pattern ^\+?256[0-9]{9}$.
idempotency_key
string
A unique key (maximum 100 characters) to make the request idempotent. If you submit a request with an idempotency_key that was already used, the API returns the original loan response instead of creating a duplicate.

Response

Returns a loan object with status: "PENDING".

Example

curl --request POST \
  --url 'https://api.saveapp.example.com/api/loans' \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "memberName": "Jane Nakato",
    "amount": 500000,
    "durationMonths": 6,
    "reason": "School fees for second term",
    "guarantor": "David Ssemakula",
    "guarantorPhone": "+256701234567",
    "idempotency_key": "loan-req-2024-06-001"
  }'

Approve a loan

Record an admin’s approval for a pending loan. Approval requires unanimous consent from all active admins in the group. Each admin must call this endpoint separately; the loan status changes to ACTIVE only after every admin has approved.
POST /api/loans/{id}/approve
This endpoint is restricted to admin users. A loan remains in PENDING status until all active admins have approved it. The API response indicates how many approvals have been recorded so far (e.g., 2/3 admins have approved).

Path parameters

id
string
required
The unique identifier of the loan to approve.

Response

success
boolean
required
true when the approval was recorded successfully.
message
string
required
A human-readable message indicating either that approval is unanimous and the loan is now ACTIVE, or showing the running tally (e.g., "2/3 admins have approved").

Example

curl --request POST \
  --url 'https://api.saveapp.example.com/api/loans/loan_abc123/approve' \
  --header 'Authorization: Bearer <admin_token>'

Reject a loan

Reject a pending loan request. Only admins can reject loans. The rejection reason is appended to the loan’s existing reason field for audit purposes.
POST /api/loans/{id}/reject

Path parameters

id
string
required
The unique identifier of the loan to reject.

Request body

reason
string
required
Explanation for the rejection. Minimum 2 characters, maximum 200 characters. This is appended to the loan record as [REJECTED: <reason>].

Response

success
boolean
required
true when the loan was rejected successfully.
message
string
required
Confirmation message, e.g. "Loan rejected".

Example

curl --request POST \
  --url 'https://api.saveapp.example.com/api/loans/loan_abc123/reject' \
  --header 'Authorization: Bearer <admin_token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "reason": "Insufficient guarantor information provided"
  }'