Using CI4 and Flutter, from scratch! we are going to build a solution for motor vehicle financing companies. in case i missed anything use useful add/implement it and note that as we build we might add or alter things for a better solution, after understanding everything we start building the database migrations, controllers and models, when done we 1st build the admin then the company portal Super Admin (owner)(web only) -informative dashboard -companies with their owners -Users -Subscription (Companies only) -User payment transactions -Subscription transactions -terms/policies Company portal -login (phone/email and Password) -Register (form: Company name, Owner phone number, Support Phone Number must be unique from owner's, email address, Car Bond Address, Upload Operating license for KYB) -informative dashboard -consumers (their customers who are consuming the services, with access to details so they can see balances make calls to remind them for payments etc) -cars (here they add cars: form (car image max 4 photos, brand, VIN, Chassis, license plate any all the relevant info about a car)) -sell car (here they assign the car to the consumer, automatically map the car details, can only map cars to users who have already registered by finding them via lookup, amount paid, balance amount, users with none verified KYC will clearly show to the company etc) -transactions (collected amounts verses balances, with withdrawal funds option) -team (share access to distribute work flow/load and follow ups) -consultation (here companies see consultation requests from the user and eligibility !companies register for free and access the portal but are limited to viewing the dashboard only until they pay the subscription fee set by the admin, the subscription fee will be required monthly !Companies to receive payment via FinFlo, requires companies to have merchant accounts with FinFlo, if user makes the payment using Mobile Money the company will have 2 options to withdraw their Money Bank or Mobile money here are the withdraw implementationsPOST: https://debit.gmpayapp.site/public/api/mobile-money/send { "msisdn": "+25670XXXXXX", //tipster enters phone number, prefill +256 they start entering from 7 "amount": 1000.00, //amount they wish to withdraw, min is 20,000 "currency": "UGX", //hard coded "description": "Carly Payout" //hard coded } Response { "success": true, "message": "Send payment in progress.", "internal_reference": "dc22a85b2c7b27a708ce6b41d5c3c195" } withdraw to bank we have to validate the payload POST: https://debit.gmpayapp.site/public/api/mobile-money/validate-bank Payload { "msisdn": "6007244078", "amount": 3000, "product_code": "ABSA_BANK_UGANDA_TRANSFER", "contact_phone": "+256768464016", "depositor_name": "John Doe", "account_name": "John Doe Savings" } Save list of banks in the DB GET: https://debit.gmpayapp.site/public/api/mobile-money/services/categorized after validation we get the validation reference and POST it to perform the depositing to Bank validation response { "success": true, "message": "Product validation successful", "customer_name": "GREEN MONDAY TECHNOLOGIES LTD", "validation_reference": "39bfb74dc79ae270", "reference": "MM_1767881538_f46ca4e70012760a", "product_code": "ABSA_BANK_UGANDA_TRANSFER", "msisdn": "6007244078", "amount": 3000 } We only take the validation response and POST it to https://debit.gmpayapp.site/public/api/mobile-money/purchase-product { "validation_reference": "ccd9cdd8db73f0f2" } Before we perform the crediting lets validate the phone number entered and our balance if the withdrawing amount is less or equal to our balance we process the transaction if not then we notify the company sorry, we are experiencing issues with the service provider. balance check api GET https://debit.gmpayapp.site/public/api/mobile-money/balance { "success": true, "balance": 4964.5, "currency": "UGX", "account_no": "REL4737AB23A9" } POST: https://debit.gmpayapp.site/public/api/mobile-money/validate { "msisdn": "+256702016859" } response { "success": true, "message": "Msisdn +256702016859 successfully validated.", "customer_name": "ABUDUL ASIIMWE", "msisdn": "+256702016859" } so these are the steps 1. Company chooses withdraw, selects bank or mobile money 2. if MM we pop a form, they set phone number and amount 2.1 if Bank, user selects bank, we set the product_code automaticall, phone number we can use the one on company account 3. Validate, we run validation and return registered name on the phone number 4. Confirm, or reset, if confirm we post to the send endpoint, if reset, we reset the form User/Consumer (Flutter app) Login/Register -Dashboard (showing financing progress and more cool features) -Bottom Nav (Home, transactions, Market place, settings) --Home this is the dashboard --Transactions user sees their payment history with details --Market Place, user can see a list of cars from various companies, can filter which company, see car details and can consult --Settings, manage profile but cant change name, email and phone, must upload National ID/Driver License/Passport) other user app functions -user can not consult with out KYC submission -user can not request for car financing -when making payment we shall have 3 options, Cash, FinFlo (i will share the API as we progress), Mobile Money (using the Mobile Money API) like i said, in case i missed something cool and it adds to the project, implement it for subscription we shall use Mobile Money Mobile Money: https://debit.gmpayapp.site/public/api/mobile-money/pay and here is the payload { "msisdn": "+256700123456", // the number should be formatted exactly as it is in the payload, we automatically handle +256 so user just starts by typing in 7XXXXX "amount": 500.00 } response { "success": true, "message": "Request payment in progress.", "internal_reference": "ec4e0161104b3394d074123d0d7a0f69", "reference": "MM_1763118029_204cadd695eb9626" } then we have the check transaction status https://debit.gmpayapp.site/public/api/mobile-money/status/{reference} response { "success": true, "transaction": { "reference": "MM_1763118029_204cadd695eb9626", "internal_reference": "ec4e0161104b3394d074123d0d7a0f69", "msisdn": "+256700123456", "amount": "500.00", "status": "SUCCESS", "created_at": "2025-11-14 14:00:30" } } "status": "SUCCESS", awards subscription "status": "FAILED", we do nothing, but notify the user transaction failed "status": "PENDING", we keep checking after a few tries we can render the transaction failed