The KYC page gets data from the endpoint /api:BVaDN9hl/kyc/get?page=1&per_page=15 which runs App\Http\Controllers\Admin\KYCController@get and displays the KYC documents uploaded to the system.
{
"data": [
{
"name": "Sam Uzima",
"email": "u******il.com",
"phone": "{"phone":"+254******77","status":"pending"}",
"profile": null,
"kid": 2416,
"kyc_status": "pending",
"subscription_status": false,
"kra": null,
"bank_statement": null,
"ID_passport": null,
"address": null,
"next_of_kin": null,
"photo": null,
"membership_number": "1005426",
"user_dob": "01/05/2003",
"kyc_created_at": "2025-03-03 11:34:41"
},
{
"name": "Wakiuru Njuguna",
"email": "
#
#
#
"kyc_created_at": "2025-01-31 12:05:55"
}
],
"links": {
"first": "http://127.0.0.1:8080/api:BVaDN9hl/kyc/get?page=1",
"last": "http://127.0.0.1:8080/api:BVaDN9hl/kyc/get?page=155",
"prev": null,
"next": "http://127.0.0.1:8080/api:BVaDN9hl/kyc/get?page=2"
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 155,
"links": [
{
"url": null,
"label": "« Previous",
"active": false
},
{
"url": "http://127.0.0.1:8080/api:BVaDN9hl/kyc/get?page=1",
"label": "1",
"active": true
},
{
"url": null,
"label": "...",
"active": false
},
{
"url": "http://127.0.0.1:8080/api:BVaDN9hl/kyc/get?page=154",
"label": "154",
"active": false
},
{
"url": "http://127.0.0.1:8080/api:BVaDN9hl/kyc/get?page=155",
"label": "155",
"active": false
},
{
"url": "http://127.0.0.1:8080/api:BVaDN9hl/kyc/get?page=2",
"label": "Next »",
"active": false
}
],
"path": "http://127.0.0.1:8080/api:BVaDN9hl/kyc/get",
"per_page": 15,
"to": 15,
"total": 2312
}
}
The Upload KYC Manually section allows administrators to upload KYC documents for users.
THe admin first looks up the user by email. This hits the endpoint /api:BVaDN9hl/kyc/upload-document which runs the App\Http\Controllers\Admin\KYCController@adminUploadDocument method and returns the user data.
{
"message": "User found",
"user": {
"kid": 1234,
"user_id": 5678,
"name": "Samuel Uzima",
"email": "uzi********il.com"
}
}
The admin then selects the document type to upload. The document types include:
Upon selecting the document type, the admin uploads the document. The document is uploaded to the endpoint /api:BVaDN9hl/kyc/upload-document which runs the App\Http\Controllers\Admin\KYCController@adminUploadDocument method and returns a success message which contains the user's KYC state
{
"message": "KRA KYC updated successfully",
"response": {
"id": 1234,
"profile": null,
"phone": {
"phone": "+254768415577",
"status": "pending"
},
"kra": {
"link": "https://africaspocket.ongea.studio/api/files/documents/67ca54a4e0c43.png",
"kra_pin": "12345",
"kra_pin_confirm": null,
"status": "approved",
"reason": ""
},
"bank_statement": null,
"address": null,
"next_of_kin": null,
"ID_passport": {
"link": "https://africaspocket.ongea.studio/api/files/documents/67c58fda7fd93.png",
"legal_name": "Sam Uzima",
"gender": "Male",
"dob": "2001-01-01",
"id_passport": "11043072",
"id_passport_confirm": null,
"status": "approved",
"reason": ""
},
"photo": null,
"status": null,
"users_id": 5305,
"created_at": "2025-01-23T14:25:20.000000Z",
"updated_at": "2025-03-07T02:06:30.000000Z",
"uploaded_by": null,
"is_manual_upload": true
}
}
In the hood, once an admin uploads a document, validation is first done, the user's App\Models\KYC model is then fetched and updated. The App\Http\Controllers\Admin\KYCController has a method approveUserKYC that updates the user's KYC status to approved automatically to reduce the manual work of approving KYC documents.
private function approveUserKYC($request)
{
try {
$context = $this->getColumnFromType($request->input('document_context'));
if ($context === null) {
return RespondWithError::make()->handle(
message: 'Document not found',
status: 404
);
}
$contextMapping = [
#
#
#
$data = $contextMapping[$context]['data'];
$message = $contextMapping[$context]['message'];
$results = ProcessUserKYCAction::run($data);
return RespondWithSuccess::make()->handle([
'message' => $message,
'response' => $results
]);
The code snippet above interacts with the App\Actions\Admin\ProcessUserKYCAction class which is responsible for processing the KYC document and updating the user's KYC status.
Context mapping is done to determine the document type and the data to be updated. The ProcessUserKYCAction class then processes the data and updates the user's KYC status.
The Download KYC Documents section allows administrators to download a CSV file containing KYC info for all users.
It hits the endpoint /api:BVaDN9hl/kyc/export which runs the App\Http\Controllers\Admin\KYCController@downloadKYCExport method and returns a CSV file containing the KYC info for all users.
public function downloadKYCExport()
{
return Excel::download(new KYCExport, 'kyc_data.csv', \Maatwebsite\Excel\Excel::CSV);
}
The Search section allows administrators to search for a user by email. This hits the endpoint /api:BVaDN9hl/kyc/get?filter%5Bemail%5D=uzima&page=1&per_page=15&search=uzima which runs the App\Http\Controllers\Admin\KYCController@get method and returns the user data.
{
"data": [
{
"name": "Sam Uzima",
"email": "u******il.com",
"phone": "{"phone":"+254******77","status":"pending"}",
"profile": null,
"kid": 2416,
"kyc_status": "pending",
"subscription_status": false,
"kra": null,
"bank_statement": null,
"ID_passport": null,
"address": null,
"next_of_kin": null,
"photo": null,
"membership_number": "1005426",
"user_dob": "01/05/2003",
"kyc_created_at": "2025-03-03 11:34:41"
}
],
"links": {
"first": "http://
public function get(Request $request)
{
$per_page = $request->per_page;
$search = $request->search;
$subscription_status = $request->subscription_status;
$kyc_status = $request->kyc_status;
$filter = User::query();
if ($search) {
$filter = User::query()
->where('firstname', 'like', '%' . $search . '%')
->orWhere('lastname', 'like', '%' . $search . '%')
->orWhere('email', 'like', '%' . $search . '%');
$users = QueryBuilder::for($filter)->pluck('id');
} else {
$users = QueryBuilder::for($filter)->pluck('id');
}
The View section allows administrators to view a user's KYC documents. It hits the endpoint /api:BVaDN9hl/kyc/user?kid=1234 which runs the App\Http\Controllers\Admin\KYCController@user method and returns the user's KYC documents.
{
"kid": 1234,
"name": "Samuel Uzima",
"email": "uzi********m",
"phone": "+25********7",
"date_joined": "Jan 23, 2025",
"last_login": "Jan 31, 2025 03:05AM",
"legal_name": "Sam Uzima",
"gender": "Male",
"dob": "2001-01-01",
"id_no": null,
"kyc_id_no": "11112",
"kyc_id_no_confirm": null,
"id_passport_decline_reason": "",
"id_no_url": "https://africaspocket.ongea.studio/api/files/documents/67c58fda7fd93.png",
"kyc_status": "Uninitiated",
"kyc_status_color": "/docs/1.0/kyc-admin/kyc#f03d3e66",
"id_status": "approved",
"passport_photo_url": null,
"kra_pin": "12345",
"kra_pin_url": "https://africaspocket.ongea.studio/api/files/documents/67ca54a4e0c43.png",
"kra_decline_reason": "",
"bank_name": null,
"account_number": null,
"bank_statement_link": null,
"bank_statement_decline_reason": null,
"postal_code": null,
"building_name": null,
"road": null,
"area": null,
"town": null,
"address_decline_reason": null,
"next_of_kin_name": " ",
"next_of_kin_first_name": null,
"next_of_kin_last_name": null,
"next_of_kin_phone": null,
"next_of_kin_relationship": null,
"next_of_kin_decline_reason": null,
"next_of_kin_dob": "07/03/2025"
}
The Process section allows administrators to process a user's KYC documents. The admin can approve or decline a user's KYC documents. The admin can also add a reason for the decline.
Process button hits the endpoint /api:BVaDN9hl/kyc/user?kid=1234 which runs the App\Http\Controllers\Admin\KYCController@user method and returns the user's KYC documents.
Each document type has its own endpoint for processing:
/api:BVaDN9hl/kyc/id-passport runs the App\Http\Controllers\Admin\KYCController@processIDNmumberKYC method/api:BVaDN9hl/kyc/kra runs the App\Http\Controllers\Admin\KYCController@processKRAKYC method/api:BVaDN9hl/kyc/bank runs the App\Http\Controllers\Admin\KYCController@processBankKYC method/api:BVaDN9hl/kyc/address runs the App\Http\Controllers\Admin\KYCController@processAddressKYC method/api:BVaDN9hl/kyc/passport-photo runs the App\Http\Controllers\Admin\KYCController@processPassportPhotoKYC method/api:BVaDN9hl/kyc/next-of-kin runs the App\Http\Controllers\Admin\KYCController@processNextOfKinKYC methodAll the methods above, after validating the submitted request, interact with the App\Actions\Admin\ProcessUserKYCAction class which is responsible for processing the KYC document and updating the user's KYC status.