15 KiB
BankFlow API Reference
This document describes the HTTP API contract for BankFlow. It is based on the requirements in bank-flow.md.
Overview
All loan routes are versioned under /api/v1. The health-check route is not versioned.
Routes
| Method | Route | Description | Success status |
|---|---|---|---|
POST |
/api/v1/loans |
Create a loan application | 201 Created |
POST |
/api/v1/loans/{loanId}/process |
Process a loan application | 200 OK |
GET |
/api/v1/loans/{loanId} |
Get a loan application | 200 OK |
GET |
/api/v1/loans/{loanId}/history |
Get processing history | 200 OK |
GET |
/health |
Check service health | 200 OK |
General conventions
Content type
Requests with a body must use JSON. Every response must include:
Content-Type: application/json
Timestamps
All timestamps use ISO 8601 format in UTC:
2026-07-15T10:00:00Z
Loan types
| Value | Description |
|---|---|
PERSONAL |
Personal loan |
BUSINESS |
Business loan |
Loan statuses
| Status | Description | Terminal for automatic processing |
|---|---|---|
SUBMITTED |
The application has been created but not processed | No |
IN_PROGRESS |
The application is being processed | No |
MANUAL_REVIEW |
The application requires a manual decision | Yes |
APPROVED |
The application has been approved | Yes |
REJECTED |
The application has been rejected | Yes |
Loan stages
| Stage | Description |
|---|---|
VALIDATION |
Validate the submitted application data |
FRAUD_CHECK |
Perform the mocked fraud check |
GUARANTOR_CHECK |
Check for a guarantor on business loans |
CREDIT_CHECK |
Evaluate the applicant's credit score |
MANAGER_APPROVAL |
Apply the mocked manager-approval rule |
Stage result type
| Result | Effect |
|---|---|
PASS |
Continue to the next applicable stage |
FAIL |
Stop processing and set the loan status to REJECTED |
MANUAL_REVIEW |
Stop processing and set the loan status to MANUAL_REVIEW |
Create a loan application
Creates and stores a new loan application. Creating an application does not execute its workflow.
POST /api/v1/loans
Request body
| Field | Type | Required | Rules |
|---|---|---|---|
customerId |
string |
Yes | Must not be empty |
amount |
integer |
Yes | Must be greater than 0 |
phone |
string |
Yes | Must contain exactly 11 digits and start with 09 |
loanType |
string |
Yes | Must be PERSONAL or BUSINESS |
monthlyIncome |
integer |
Yes | Must be greater than or equal to 0 |
creditScore |
integer |
Yes | Must be between 0 and 1000, inclusive |
hasGuarantor |
boolean |
Yes | Indicates whether the applicant has a guarantor |
{
"customerId": "C-1001",
"amount": 400000000,
"phone": "09121234567",
"loanType": "PERSONAL",
"monthlyIncome": 50000000,
"creditScore": 720,
"hasGuarantor": false
}
Processing rules
- The service generates a unique
loanId. - The initial status is
SUBMITTED. - The initial workflow stage is
VALIDATION. - Business validation is deferred until the workflow is processed.
- An invalid field value does not produce an HTTP
400response during creation. It causes theVALIDATIONstage to fail when the application is processed. - A malformed JSON document produces an HTTP
400response.
Success response
HTTP/1.1 201 Created
Content-Type: application/json
{
"loanId": "L-10001",
"status": "SUBMITTED",
"currentStage": "VALIDATION"
}
Response fields
| Field | Type | Description |
|---|---|---|
loanId |
string |
Unique identifier generated by the service |
status |
string |
Current loan status; initially SUBMITTED |
currentStage |
string |
Current workflow stage; initially VALIDATION |
Malformed JSON response
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "INVALID_REQUEST"
}
Process a loan application
Processes an application from its current workflow stage until it reaches a terminal automatic-processing status.
POST /api/v1/loans/{loanId}/process
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
loanId |
string |
Yes | Unique loan application identifier |
This route does not accept a request body.
Workflow rules
All applications begin with the following stages:
VALIDATION → FRAUD_CHECK
The remaining route depends on the loan type:
PERSONAL:
VALIDATION → FRAUD_CHECK → CREDIT_CHECK → [MANAGER_APPROVAL] → APPROVED
BUSINESS:
VALIDATION → FRAUD_CHECK → GUARANTOR_CHECK → CREDIT_CHECK
→ [MANAGER_APPROVAL] → APPROVED
MANAGER_APPROVAL runs only when amount is greater than the configured managerApprovalThreshold.
Processing stops immediately when a stage returns FAIL or MANUAL_REVIEW.
Idempotency rules
This operation must be idempotent.
If the application is already APPROVED, REJECTED, or MANUAL_REVIEW:
- no workflow stage is executed again;
- no duplicate history record is created;
- the existing status is not changed;
- the current application state is returned with
200 OK.
Approved response
HTTP/1.1 200 OK
Content-Type: application/json
{
"loanId": "L-10001",
"status": "APPROVED",
"currentStage": null
}
Rejected response
HTTP/1.1 200 OK
Content-Type: application/json
{
"loanId": "L-10001",
"status": "REJECTED",
"currentStage": null
}
Manual-review response
HTTP/1.1 200 OK
Content-Type: application/json
{
"loanId": "L-10001",
"status": "MANUAL_REVIEW",
"currentStage": null
}
Loan-not-found response
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": "LOAN_NOT_FOUND"
}
Get a loan application
Returns the submitted data and current processing state of a loan application.
GET /api/v1/loans/{loanId}
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
loanId |
string |
Yes | Unique loan application identifier |
Success response
HTTP/1.1 200 OK
Content-Type: application/json
{
"loanId": "L-10001",
"customerId": "C-1001",
"amount": 400000000,
"phone": "09121234567",
"loanType": "PERSONAL",
"monthlyIncome": 50000000,
"creditScore": 720,
"hasGuarantor": false,
"status": "APPROVED",
"currentStage": null,
"createdAt": "2026-07-15T10:00:00Z",
"updatedAt": "2026-07-15T10:00:03Z"
}
Response fields
| Field | Type | Nullable | Description |
|---|---|---|---|
loanId |
string |
No | Unique loan application identifier |
customerId |
string |
No | Customer identifier |
amount |
integer |
No | Requested loan amount |
phone |
string |
No | Applicant's mobile number |
loanType |
string |
No | Loan type |
monthlyIncome |
integer |
No | Applicant's monthly income |
creditScore |
integer |
No | Applicant's credit score |
hasGuarantor |
boolean |
No | Whether the applicant has a guarantor |
status |
string |
No | Current loan status |
currentStage |
string |
Yes | Current workflow stage; null after processing stops |
createdAt |
string |
No | Creation timestamp in ISO 8601 UTC format |
updatedAt |
string |
No | Last-update timestamp in ISO 8601 UTC format |
Loan-not-found response
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": "LOAN_NOT_FOUND"
}
Get processing history
Returns workflow stage executions in chronological order.
GET /api/v1/loans/{loanId}/history
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
loanId |
string |
Yes | Unique loan application identifier |
History rules
- Records are ordered by
timestampfrom oldest to newest. - A workflow stage is recorded at most once for an application.
- Reprocessing a terminal application does not add history records.
reasoncontainsSUCCESSfor a successful stage or the applicable business error code for a failed validation.
Success response
HTTP/1.1 200 OK
Content-Type: application/json
[
{
"stage": "VALIDATION",
"result": "PASS",
"timestamp": "2026-07-15T10:00:00Z",
"reason": "SUCCESS"
},
{
"stage": "FRAUD_CHECK",
"result": "PASS",
"timestamp": "2026-07-15T10:00:01Z",
"reason": "SUCCESS"
},
{
"stage": "CREDIT_CHECK",
"result": "PASS",
"timestamp": "2026-07-15T10:00:02Z",
"reason": "SUCCESS"
}
]
History record fields
| Field | Type | Description |
|---|---|---|
stage |
string |
Name of the executed workflow stage |
result |
string |
PASS, FAIL, or MANUAL_REVIEW |
timestamp |
string |
Execution time in ISO 8601 UTC format |
reason |
string |
Reason or business error code associated with the result |
Loan-not-found response
HTTP/1.1 404 Not Found
Content-Type: application/json
{
"error": "LOAN_NOT_FOUND"
}
Health check
Reports whether the service is available.
GET /health
Success response
HTTP/1.1 200 OK
Content-Type: application/json
{
"status": "UP"
}
Business rules
Validation
The VALIDATION stage applies the following rules:
| Field | Rule | Failure reason |
|---|---|---|
customerId |
Required and not empty | INVALID_CUSTOMER_ID |
amount |
Greater than 0 |
INVALID_AMOUNT |
phone |
Exactly 11 digits, starts with 09, and contains digits only |
INVALID_PHONE |
loanType |
PERSONAL or BUSINESS |
INVALID_LOAN_TYPE |
monthlyIncome |
Greater than or equal to 0 |
INVALID_MONTHLY_INCOME |
creditScore |
Between 0 and 1000, inclusive |
INVALID_CREDIT_SCORE |
Any validation failure produces a FAIL stage result and changes the application status to REJECTED.
Fraud check
The FRAUD_CHECK stage is mocked using customerId:
| Rule | Result |
|---|---|
Starts with FRAUD |
FAIL |
Starts with REVIEW |
MANUAL_REVIEW |
| Any other value | PASS |
Guarantor check
The GUARANTOR_CHECK stage runs only for BUSINESS loans:
| Rule | Result |
|---|---|
hasGuarantor is false |
FAIL |
hasGuarantor is true |
PASS |
Credit check
The default credit-score rules are:
| Rule | Result |
|---|---|
creditScore < 500 |
FAIL |
500 <= creditScore < 650 |
MANUAL_REVIEW |
creditScore >= 650 |
PASS |
The score boundaries must be loaded from configuration and must not be hard-coded.
Manager approval
MANAGER_APPROVAL runs when the requested amount is greater than the configured managerApprovalThreshold.
| Rule | Result |
|---|---|
amount > monthlyIncome × incomeMultiplier |
FAIL |
| Otherwise | PASS |
Both managerApprovalThreshold and incomeMultiplier must be loaded from configuration.
Error codes
HTTP errors
| HTTP status | Error code | Description |
|---|---|---|
400 Bad Request |
INVALID_REQUEST |
The request body is not valid JSON |
404 Not Found |
LOAN_NOT_FOUND |
No loan application exists for the supplied loanId |
HTTP error responses use this shape:
{
"error": "LOAN_NOT_FOUND"
}
Business validation errors
Business validation errors do not produce HTTP 400 responses during loan creation. They are recorded as the reason of the failed VALIDATION history entry.
| Error code | Description |
|---|---|
INVALID_AMOUNT |
The requested amount is invalid |
INVALID_PHONE |
The mobile number is invalid |
INVALID_CUSTOMER_ID |
The customer identifier is invalid |
INVALID_LOAN_TYPE |
The loan type is invalid |
INVALID_CREDIT_SCORE |
The credit score is invalid |
INVALID_MONTHLY_INCOME |
The monthly income is invalid |