Payment Gateway for the Mifos Platform and Beyonic Payment Service
Implement the Mifos payment gateway service to support the following use cases:
Real time disbursement
Batch disbursement
Customer initiated payments
Develop a Payment Gateway portal for the payment gateway.
Develop a particular mobile money integration on the payment gateway to show it works.
Document the api for the payment gateway.
Implemented a payment gateway which supports the following use cases:
Real time disbursement
Batch disbursement
Customer initiated payments
Developed a mobile money integration with Beyonic to test the payment gateway.
Implementing the payment gateway portal which will be used by MFIs and MMPs.
Documentating the payment gateway's api to facilitate integration with other MMP apis.
Implementing test on the payment gateway and Beyonic Payment service.
Setup information for both the Payment gateway and Beyonic's payment service
Download MySql 5.6 and above.
Download Java(JDK) 1.8 and above.
Download an IDE that support gradle, most preferably Intellij and turn on annotation processing in your settings.
Clone the code from the above repository
Upload the project into your favorite IDE as a Gradle project.
Run gradle build and then run the application.
Open your mysql and create a database called mifos-payment-gateway
Go to application.properties file in the resource folder of our application.
- Change the spring.datasource.username
to your database username and the spring.datasource.password
to your database password.
API documentation for Payment Gateway
Customer Initiated payment (Loan Repayment)
Example Request:
POST http://localhost:8080/inbound/requests? tenant=default
Content-Type: application/json
Request Body:
{
" id" : 1,
" transactType" : " LOAN_REPAYMENT" ,
" paymentMethod" : " mobile money" ,
" paymentMethodType" : " beyonic" ,
" mmpId" : 1,
" mfiId" : 1,
" sourceRef" : " +233267881050" ,
" destinationRef" : " +80000000001" ,
" fineractAccNo" : " 000000039" ,
" fineractClientId" : 1,
" amount" : 10,
" transactionReason" : " Test Beyonic" ,
" externalSystId" : 0,
" comments" : " outgoing payment" ,
" requestDtm" : " 1503492596" ,
" requestIpAddress" : " 127.0.0.1" ,
" inboundStatusId" : 0,
" inboundStatusDtm" : " 1503492596"
}
Example Response:
{
" id" : null,
" code" : " 2100" ,
" description" : " Request was received" ,
" statusCategory" : 3
}
Customer Initiated payment (Voluntary Customer Saving)
Example Request:
POST http://localhost:8080/inbound/requests? tenant=default
Content-Type: application/json
Request Body:
{
" id" : 1,
" transactType" : " VOLUNTARY_SAVINGS" ,
" paymentMethod" : " mobile money" ,
" paymentMethodType" : " beyonic" ,
" mmpId" : 1,
" mfiId" : 1,
" sourceRef" : " +233267881050" ,
" destinationRef" : " +80000000001" ,
" fineractAccNo" : " 000000001" ,
" fineractClientId" : 1,
" amount" : 10,
" transactionReason" : " Test Beyonic" ,
" externalSystId" : 0,
" comments" : " outgoing payment" ,
" requestDtm" : " 1503492596" ,
" requestIpAddress" : " 127.0.0.1" ,
" inboundStatusId" : 0,
" inboundStatusDtm" : " 1503492596"
}
Example Response:
{
" id" : null,
" code" : " 2100" ,
" description" : " Request was received" ,
" statusCategory" : 3
}
Customer Initiated payment (Recurring Customer deposit)
Example Request:
POST http://localhost:8080/inbound/requests? tenant=default
Content-Type: application/json
Request Body:
{
" id" : 1,
" transactType" : " RECURRING_DEPOSIT" ,
" paymentMethod" : " mobile money" ,
" paymentMethodType" : " beyonic" ,
" mmpId" : 1,
" mfiId" : 1,
" sourceRef" : " +233267881050" ,
" destinationRef" : " +80000000001" ,
" fineractAccNo" : " abc000000047" ,
" fineractClientId" : 1,
" amount" : 10,
" transactionReason" : " Test Beyonic" ,
" externalSystId" : 0,
" comments" : " outgoing payment" ,
" requestDtm" : " 1503492596" ,
" requestIpAddress" : " 127.0.0.1" ,
" inboundStatusId" : 0,
" inboundStatusDtm" : " 1503492596"
}
Example Response:
{
" id" : null,
" code" : " 2100" ,
" description" : " Request was received" ,
" statusCategory" : 3
}
Real time loan disbursement
Example Request:
POST http://localhost:8080/outbound/requests? tenant=default
Content-Type: application/json
Request Body:
{
" id" : 1,
" transactType" : " DISBURSEMENT" ,
" paymentMethod" : " mobile money" ,
" paymentMethodType" : " beyonic" ,
" mmpId" : 1,
" mfiId" : 1,
" sourceRef" : " +233267881050" ,
" destinationRef" : " +80000000001" ,
" fineractAccNo" : " abc000000047" ,
" fineractClientId" : 1,
" amount" : 10,
" transactionReason" : " Test Beyonic" ,
" externalSystId" : 0,
" comments" : " outgoing payment" ,
" requestDtm" : " 1503492596" ,
" requestIpAddress" : " 127.0.0.1" ,
" outboundStatusId" : 0,
" outboundStatusDtm" : " 1503492596" ,
" reverseStatusId" : 0,
" reverseStatusIdDtm" : " 1503492596"
}
Example Response:
{
" id" : null,
" code" : " 2100" ,
" description" : " Request was received" ,
" statusCategory" : 3
}
Get recurring deposit account
Example Request:
POST http://localhost:8080/recurringDepositAccounts? tenant=default
Content-Type: application/json
Request Body:
{
" accountNumber" : " 000000017"
}
Example Response:
{
" id" : 1,
" accountNo" : " RD000023" ,
" externalId" : " RD-23" ,
" clientId" : 1,
" clientName" : " Sangamesh N" ,
" savingsProductId" : 3,
" savingsProductName" : " RD01" ,
" fieldOfficerId" : 0,
" status" : {
" id" : 100,
" code" : " savingsAccountStatusType.submitted.and.pending.approval" ,
" value" : " Submitted and pending approval" ,
" submittedAndPendingApproval" : true,
" approved" : false,
" rejected" : false,
" withdrawnByApplicant" : false,
" active" : false,
" closed" : false,
" prematureClosed" : false,
" transferInProgress" : false,
" transferOnHold" : false
},
" timeline" : {
" submittedOnDate" : [
2014,
3,
1
],
" submittedByUsername" : " mifos" ,
" submittedByFirstname" : " App" ,
" submittedByLastname" : " Administrator"
},
" currency" : {
" code" : " USD" ,
" name" : " US Dollar" ,
" decimalPlaces" : 2,
" inMultiplesOf" : 1,
" displaySymbol" : " $" ,
" nameCode" : " currency.USD" ,
" displayLabel" : " US Dollar ($)"
},
" interestCompoundingPeriodType" : {
" id" : 4,
" code" : " savings.interest.period.savingsCompoundingInterestPeriodType.monthly" ,
" value" : " Monthly"
},
" interestPostingPeriodType" : {
" id" : 4,
" code" : " savings.interest.posting.period.savingsPostingInterestPeriodType.monthly" ,
" value" : " Monthly"
},
" interestCalculationType" : {
" id" : 1,
" code" : " savingsInterestCalculationType.dailybalance" ,
" value" : " Daily Balance"
},
" interestCalculationDaysInYearType" : {
" id" : 365,
" code" : " savingsInterestCalculationDaysInYearType.days365" ,
" value" : " 365 Days"
},
" preClosurePenalApplicable" : false,
" minDepositTerm" : 3,
" maxDepositTerm" : 4,
" minDepositTermType" : {
" id" : 2,
" code" : " deposit.term.savingsPeriodFrequencyType.months" ,
" value" : " Months"
},
" maxDepositTermType" : {
" id" : 3,
" code" : " deposit.term.savingsPeriodFrequencyType.years" ,
" value" : " Years"
},
" recurringDepositAmount" : 100,
" recurringDepositFrequency" : 1,
" expectedFirstDepositOnDate" : [
2014,
4,
2
],
" recurringDepositFrequencyType" : {
" id" : 2,
" code" : " recurring.deposit.savingsPeriodFrequencyType.months" ,
" value" : " Months"
},
" depositPeriod" : 6,
" depositPeriodFrequency" : {
" id" : 2,
" code" : " deposit.period.savingsPeriodFrequencyType.months" ,
" value" : " Months"
},
" summary" : {
" currency" : {
" code" : " USD" ,
" name" : " US Dollar" ,
" decimalPlaces" : 2,
" inMultiplesOf" : 1,
" displaySymbol" : " $" ,
" nameCode" : " currency.USD" ,
" displayLabel" : " US Dollar ($)"
},
" accountBalance" : 0
},
" accountChart" : {
" id" : 4,
" fromDate" : [
2013,
10,
2
],
" accountId" : 5,
" accountNumber" : " RD000023" ,
" chartSlabs" : [
{
" id" : 13,
" periodType" : {
" id" : 0,
" code" : " interestChartPeriodType.days" ,
" value" : " Days"
},
" fromPeriod" : 181,
" toPeriod" : 365,
" annualInterestRate" : 5.5,
" currency" : {
" code" : " USD" ,
" name" : " US Dollar" ,
" decimalPlaces" : 2,
" displaySymbol" : " $" ,
" nameCode" : " currency.USD" ,
" displayLabel" : " US Dollar ($)"
}
},
{
" id" : 12,
" periodType" : {
" id" : 0,
" code" : " interestChartPeriodType.days" ,
" value" : " Days"
},
" fromPeriod" : 1,
" toPeriod" : 180,
" annualInterestRate" : 5,
" currency" : {
" code" : " USD" ,
" name" : " US Dollar" ,
" decimalPlaces" : 2,
" displaySymbol" : " $" ,
" nameCode" : " currency.USD" ,
" displayLabel" : " US Dollar ($)"
}
},
{
" id" : 11,
" periodType" : {
" id" : 0,
" code" : " interestChartPeriodType.days" ,
" value" : " Days"
},
" fromPeriod" : 366,
" annualInterestRate" : 6,
" currency" : {
" code" : " USD" ,
" name" : " US Dollar" ,
" decimalPlaces" : 2,
" displaySymbol" : " $" ,
" nameCode" : " currency.USD" ,
" displayLabel" : " US Dollar ($)"
}
}
],
" periodTypes" : [
{
" id" : 0,
" code" : " interestChartPeriodType.days" ,
" value" : " Days"
},
{
" id" : 1,
" code" : " interestChartPeriodType.weeks" ,
" value" : " Weeks"
},
{
" id" : 2,
" code" : " interestChartPeriodType.months" ,
" value" : " Months"
},
{
" id" : 3,
" code" : " interestChartPeriodType.years" ,
" value" : " Years"
}
]
}
}
Get customer loan account
Example Request:
POST http://localhost:8080//loans? tenant=default
Content-Type: application/json
Request Body:
{
" accountNumber" : " 000000017"
}
Example Response:
{
" id" : 1,
" accountNo" : " 000000001" ,
" status" : {
" id" : 300,
" code" : " loanStatusType.active" ,
" value" : " Active" ,
" pendingApproval" : false,
" waitingForDisbursal" : false,
" active" : true,
" closedObligationsMet" : false,
" closedWrittenOff" : false,
" closedRescheduled" : false,
" closed" : false,
" overpaid" : false
},
" clientId" : 1,
" clientName" : " Kampala first Client" ,
" clientOfficeId" : 2,
" loanProductId" : 1,
" loanProductName" : " Kampala Product (with cash accounting)" ,
" loanProductDescription" : " Typical Kampala loan product with cash accounting enabled for testing." ,
" loanPurposeId" : 22,
" loanPurposeName" : " option.HousingImprovement" ,
" loanOfficerId" : 2,
" loanOfficerName" : " LoanOfficer, Kampala" ,
" loanType" : {
" id" : 1,
" code" : " loanType.individual" ,
" value" : " Individual"
},
" currency" : {
" code" : " UGX" ,
" name" : " Uganda Shilling" ,
" decimalPlaces" : 2,
" displaySymbol" : " USh" ,
" nameCode" : " currency.UGX" ,
" displayLabel" : " Uganda Shilling (USh)"
},
" principal" : 1000000,
" termFrequency" : 12,
" termPeriodFrequencyType" : {
" id" : 2,
" code" : " termFrequency.periodFrequencyType.months" ,
" value" : " Months"
},
" numberOfRepayments" : 12,
" repaymentEvery" : 1,
" repaymentFrequencyType" : {
" id" : 2,
" code" : " repaymentFrequency.periodFrequencyType.months" ,
" value" : " Months"
},
" interestRatePerPeriod" : 24,
" interestRateFrequencyType" : {
" id" : 3,
" code" : " interestRateFrequency.periodFrequencyType.years" ,
" value" : " Per year"
},
" annualInterestRate" : 24,
" amortizationType" : {
" id" : 1,
" code" : " amortizationType.equal.installments" ,
" value" : " Equal installments"
},
" interestType" : {
" id" : 1,
" code" : " interestType.flat" ,
" value" : " Flat"
},
" interestCalculationPeriodType" : {
" id" : 1,
" code" : " interestCalculationPeriodType.same.as.repayment.period" ,
" value" : " Same as repayment period"
},
" transactionProcessingStrategyId" : 2,
" timeline" : {
" submittedOnDate" : [
2012,
4,
3
],
" submittedByUsername" : " admin" ,
" submittedByFirstname" : " App" ,
" submittedByLastname" : " Administrator" ,
" approvedOnDate" : [
2012,
4,
3
],
" approvedByUsername" : " admin" ,
" approvedByFirstname" : " App" ,
" approvedByLastname" : " Administrator" ,
" expectedDisbursementDate" : [
2012,
4,
10
],
" actualDisbursementDate" : [
2012,
4,
10
],
" disbursedByUsername" : " admin" ,
" disbursedByFirstname" : " App" ,
" disbursedByLastname" : " Administrator" ,
" expectedMaturityDate" : [
2013,
4,
10
]
},
" summary" : {
" currency" : {
" code" : " UGX" ,
" name" : " Uganda Shilling" ,
" decimalPlaces" : 2,
" displaySymbol" : " USh" ,
" nameCode" : " currency.UGX" ,
" displayLabel" : " Uganda Shilling (USh)"
},
" principalDisbursed" : 1000000,
" principalPaid" : 0,
" principalWrittenOff" : 0,
" principalOutstanding" : 1000000,
" principalOverdue" : 833333.3,
" interestCharged" : 240000,
" interestPaid" : 0,
" interestWaived" : 0,
" interestWrittenOff" : 0,
" interestOutstanding" : 240000,
" interestOverdue" : 200000,
" feeChargesCharged" : 18000,
" feeChargesDueAtDisbursementCharged" : 0,
" feeChargesPaid" : 0,
" feeChargesWaived" : 0,
" feeChargesWrittenOff" : 0,
" feeChargesOutstanding" : 18000,
" feeChargesOverdue" : 15000,
" penaltyChargesCharged" : 0,
" penaltyChargesPaid" : 0,
" penaltyChargesWaived" : 0,
" penaltyChargesWrittenOff" : 0,
" penaltyChargesOutstanding" : 0,
" penaltyChargesOverdue" : 0,
" totalExpectedRepayment" : 1258000,
" totalRepayment" : 0,
" totalExpectedCostOfLoan" : 258000,
" totalCostOfLoan" : 0,
" totalWaived" : 0,
" totalWrittenOff" : 0,
" totalOutstanding" : 1258000,
" totalOverdue" : 1048333.3,
" overdueSinceDate" : [
2012,
5,
10
],
" linkedAccount" :{
" id" :1,
" accountNo" :" 000000001"
},
" disbursementDetails" :[{" id" :71," expectedDisbursementDate" :[2013,11,1]," principal" :22000.000000," approvedPrincipal" :22000.000000}],
" fixedEmiAmount" :1100.000000,
" maxOutstandingLoanBalance" :35000,
" canDisburse" :false,
" emiAmountVariations" : [],
" inArrears" : true,
" isNPA" :false,
" overdueCharges" : [
{
" id" : 20,
" name" : " overdraft penality" ,
" active" : true,
" penalty" : true,
" currency" : {
" code" : " USD" ,
" name" : " US Dollar" ,
" decimalPlaces" : 2,
" displaySymbol" : " $" ,
" nameCode" : " currency.USD" ,
" displayLabel" : " US Dollar ($)"
},
" amount" : 3.000000,
" chargeTimeType" : {
" id" : 9,
" code" : " chargeTimeType.overdueInstallment" ,
" value" : " overdue fees"
},
" chargeAppliesTo" : {
" id" : 1,
" code" : " chargeAppliesTo.loan" ,
" value" : " Loan"
},
" chargeCalculationType" : {
" id" : 2,
" code" : " chargeCalculationType.percent.of.amount" ,
" value" : " % Amount"
},
" chargePaymentMode" : {
" id" : 0,
" code" : " chargepaymentmode.regular" ,
" value" : " Regular"
},
" feeInterval" : 2,
" feeFrequency" : {
" id" : 1,
" code" : " feeFrequencyperiodFrequencyType.weeks" ,
" value" : " Weeks"
}
}
]
}
}
Get voluntary saving account
Example Request:
POST http://localhost:8080//voluntarySavingAccounts? tenant=default
Content-Type: application/json
Request Body:
{
" accountNumber" : " 000000017"
}
Example Response:
{
" id" : 1,
" accountNo" : " 000000001" ,
" clientId" : 1,
" clientName" : " small business" ,
" savingsProductId" : 1,
" savingsProductName" : " Passbook Savings" ,
" fieldOfficerId" : 0,
" status" : {
" id" : 100,
" code" : " savingsAccountStatusType.submitted.and.pending.approval" ,
" value" : " Submitted and pending approval" ,
" submittedAndPendingApproval" : true,
" approved" : false,
" rejected" : false,
" withdrawnByApplicant" : false,
" active" : false,
" closed" : false
},
" timeline" : {
" submittedOnDate" : [
2013,
3,
1
]
},
" currency" : {
" code" : " USD" ,
" name" : " US Dollar" ,
" decimalPlaces" : 2,
" displaySymbol" : " $" ,
" nameCode" : " currency.USD" ,
" displayLabel" : " US Dollar ($)"
},
" nominalAnnualInterestRate" : 5,
" interestCompoundingPeriodType" : {
" id" : 1,
" code" : " savings.interest.period.savingsCompoundingInterestPeriodType.daily" ,
" value" : " Daily"
},
" interestPostingPeriodType" : {
" id" : 4,
" code" : " savings.interest.posting.period.savingsPostingInterestPeriodType.monthly" ,
" value" : " Monthly"
},
" interestCalculationType" : {
" id" : 1,
" code" : " savingsInterestCalculationType.dailybalance" ,
" value" : " Daily Balance"
},
" interestCalculationDaysInYearType" : {
" id" : 365,
" code" : " savingsInterestCalculationDaysInYearType.days365" ,
" value" : " 365 Days"
},
" summary" : {
" currency" : {
" code" : " USD" ,
" name" : " US Dollar" ,
" decimalPlaces" : 2,
" displaySymbol" : " $" ,
" nameCode" : " currency.USD" ,
" displayLabel" : " US Dollar ($)"
},
" accountBalance" : 0,
" availableBalance" : 0
}
}
API documentation for Beyonic Payment Service
Outgoing Payment to Beyonic
```sh
Example Request:
POST http://localhost:8040/outbound/payments
Content-Type: application/json
Request Body:
{
"id" : 1,
"transactType" : "DISBURSEMENT",
"paymentMethod" : "mobile money",
"paymentMethodType" : "beyonic",
"mmpId" : 1,
"mfiId" : 1,
"sourceRef" : "+233267881050",
"destinationRef" : "+80000000001",
"fineractAccNo" : "accno123",
"fineractClientId" : 1,
"amount" : 10,
"transactionReason" : "Test Beyonic",
"externalSystId" : 0,
"comments" : "outgoing payment",
"requestDtm" : "1503492596",
"requestIpAddress" : "127.0.0.1",
"outboundStatusId" : 1,
"outboundStatusDtm" : "1503492596",
"reverseStatusId" : 1,
"reverseStatusIdDtm" : "1503492596"
}
Example Response:
{
"id": null,
"code": "2100",
"description": "Request was received",
"statusCategory": 1
}
* Beyonic Incoming payment from a client.
```sh
Example Request:
POST http://localhost:8040/collections
Content-Type: application/json
Request Body:
{
"hook": {
"id": 53,
"created": "2015-08-01T16:56:29Z",
"updated": "2015-08-01T16:56:29Z",
"event": "collection.received",
"target": "https://localhost:8040/collections",
"user": 42
},
"data": {
"id": 82,
"remote_transaction_id": "1485758785",
"organization": 1,
"amount": "2000.0000",
"currency": 2,
"phonenumber": "+80000000001",
"payment_date": "2015-07-14T09:57:44Z",
"reference": "default123456789",
"status": "successful",
"created": "2015-07-14T15:19:05Z",
"author": null,
"modified": "2015-08-20T16:48:51Z",
"updated_by": null
}
}
Example Response:
{
"id": null,
"code": "2100",
"description": "Request was received",
"statusCategory": 1
}