Skip to content

Maker-Checker Approval Workflow

The Maker-Checker system (also called the 4-eyes principle) requires that certain operations are submitted by one user (the maker) and approved by a different user (the checker) before they take effect. This is a standard internal control requirement for regulated financial institutions.


How It Works

  1. A maker initiates an action - for example, approving a loan
  2. Instead of executing immediately, the action is placed in a pending queue
  3. A checker (a different user with the appropriate permission) reviews the pending action
  4. The checker approves or rejects it
  5. On approval, the action executes; on rejection, it is discarded and the maker is notified

The maker and checker must be different users. A user cannot approve their own submissions.


Enabling Maker-Checker Globally

Maker-Checker must first be enabled at the system level via the Global Configuration API:

bash
PUT /fineract-provider/api/v1/configurations/{configId}
Authorization: Basic <base64>
Fineract-Platform-TenantId: default
Content-Type: application/json
json
{
  "enabled": true
}

Find the Maker-Checker configuration ID first:

bash
GET /fineract-provider/api/v1/configurations

Look for the entry with "name": "maker-checker" and use its id.

Disabled by default

Maker-Checker is disabled on a fresh Fineract installation. Enabling it immediately affects all task types that have been configured to require approval.


Configuring Which Tasks Require Approval

Not all operations need to go through maker-checker. Configure it per task type:

bash
GET /fineract-provider/api/v1/makercheckers

This returns all auditable task types with their current makerCheckerTask flag. To require approval for a specific task:

bash
PUT /fineract-provider/api/v1/makercheckers/{taskId}
json
{
  "makerCheckerTask": true
}

Commonly configured task types

TaskRecommended for maker-checker
Loan application submissionOptional
Loan approvalYes - regulated environments
Loan disbursementYes - high value
Loan write-offYes - irreversible
Savings withdrawalYes - above threshold
Journal entry postingYes - accounting integrity
User creationOptional
Role/permission changesYes
Client creationOptional
Charge waiverYes

Roles and Permissions

Two distinct permissions control maker-checker participation:

PermissionCodeWho needs it
Submit (maker)Standard operation permission (e.g. APPROVE_LOAN)Anyone submitting actions for approval
Approve/reject (checker)CHECKER_SUPER_USER or task-specific checker permissionCheckers only

A user with APPROVE_LOAN but without checker permission can submit loan approvals for review. A user with checker permission can approve or reject them.

Typically:

  • Loan officers have maker permissions - they submit actions
  • Branch managers or supervisors have checker permissions - they approve
  • Super users have both (but should not approve their own actions)

The Checker Inbox

Pending maker-checker items accumulate in the Checker Inbox. Query it via:

bash
GET /fineract-provider/api/v1/audits?processingResult=2

processingResult=2 returns items in awaiting approval state.

Each item includes:

json
{
  "id": 1234,
  "actionName": "APPROVE",
  "entityName": "LOAN",
  "resourceId": 567,
  "maker": "loan.officer",
  "madeOnDate": "2025-03-01T10:30:00Z",
  "processingResult": "Awaiting Approval"
}

Approving a Pending Action

bash
POST /fineract-provider/api/v1/audits/{auditId}?command=approve

No request body required. The original action executes immediately upon approval.


Rejecting a Pending Action

bash
POST /fineract-provider/api/v1/audits/{auditId}?command=reject

The pending action is discarded. The maker will see the rejection when they query their submission history.


Bulk Approval

For high-volume environments, checkers can approve multiple items at once. Retrieve all pending items, filter for the desired subset, and approve each:

bash
# Get all pending loan approvals
GET /fineract-provider/api/v1/audits?processingResult=2&entityName=LOAN&actionName=APPROVE

# Approve each
POST /fineract-provider/api/v1/audits/{auditId1}?command=approve
POST /fineract-provider/api/v1/audits/{auditId2}?command=approve

Viewing the Audit Trail

All maker-checker submissions - approved, rejected, and pending - are retained in the audit log:

bash
# All audit entries for a specific loan
GET /fineract-provider/api/v1/audits?entityName=LOAN&resourceId={loanId}

# All actions by a specific user
GET /fineract-provider/api/v1/audits?makerId={userId}

# All actions approved by a checker
GET /fineract-provider/api/v1/audits?checkerId={userId}

The audit log is permanent - entries cannot be deleted - which is important for regulatory compliance.


Processing Result Codes

CodeMeaning
1Approved
2Awaiting approval
3Rejected
4Error during execution

Maker-Checker and API Integrations

When maker-checker is enabled for a task type, API calls that trigger that task will return a 200 OK with a response indicating the action is pending rather than executed:

json
{
  "officeId": 1,
  "clientId": 45,
  "loanId": 123,
  "resourceId": 1234,
  "subResourceId": null
}

The resourceId here is the audit entry ID, not the loan ID. Your integration must detect this and either:

  • Poll GET /fineract-provider/api/v1/audits/{resourceId} until processingResult changes from 2
  • Or notify a human checker to review the inbox

Integration impact

Enabling maker-checker on operations that your integration calls synchronously will break the synchronous flow - the operation will not have executed when the API returns. Always test integrations against a maker-checker enabled environment before production.


Disabling Maker-Checker for Specific Environments

For development or testing environments where the approval loop is not needed:

bash
PUT /fineract-provider/api/v1/configurations/{makercheckerConfigId}
json
{
  "enabled": false
}

Or disable it per task type to leave global maker-checker on but skip it for low-risk operations.