Skip to main content

Individuals

Overview

Individual endpoints support creating and working with individual records involved in verification and compliance workflows.

Individual FICA Guide

Table of Contents

  1. Overview
  2. Authentication
  3. API Workflow
  4. Step-by-Step Implementation Guide
  5. Endpoint Reference
  6. Request/Response Examples
  7. Error Handling
  8. Best Practices

Overview

The eFICA Individual API allows you to create and manage FICA (Financial Intelligence Centre Act) compliance records for individual clients. This API provides a complete workflow from initial client registration through document verification to final onboarding decisions.

Key Features

  • Complete FICA Workflow: End-to-end individual client onboarding
  • AML Screening: Automated Anti-Money Laundering checks
  • External Validation: Integration with credit bureaus for identity verification
  • Document Management: Upload, view, and manage client documents
  • PEP & Sanctions Screening: Politically Exposed Persons and sanctions list checks
  • Onboarding Decisions: Approve, decline, or refer clients for review

Base URLs

  • Sandbox: https://sandboxapi.efica.co.za
  • Production: https://loginapi.efica.co.za

API Version

All endpoints are under /api/v1/individual


Authentication

All endpoints require OAuth2 Bearer token authentication. Include the token in the Authorization header:

Authorization: Bearer <your-oauth2-token>

For details on obtaining OAuth2 tokens, refer to the OAuth2 Integration Guide.

Important: If there is insufficient balance in your account, the individual record will not be created in Step 1.


API Workflow

The following diagram illustrates the complete workflow for onboarding an individual client:


Step-by-Step Implementation Guide

Step 1: Create Individual Record (Mandatory)

Endpoint: POST /api/v1/individual

Create a new individual client record. This is the first step in the onboarding process.

Important Notes:

  • If your account has insufficient balance, the record will not be created
  • The response contains the individual id (UUID) which is required for all subsequent steps
  • Store this id for use in all following API calls

Request Body: See Create Individual Request section below.

Response: Returns the individual UUID as id

{
"id": "123e4567-e89b-12d3-a456-426614174000"
}

Step 2: Execute AML Screening (Mandatory)

Endpoint: POST /api/v1/individual/:id/aml-screening

Run an Anti-Money Laundering screening search on the client. This uses data from the individual record created in Step 1 (firstName, lastName, clientEmail).

Path Parameters:

  • id (string, required): The individual UUID from Step 1

Request Body: None (uses data from individual record)

Response: Returns AML screening results including matched entities and web search results.

{
"matchedNumber": 0,
"matchedEntities": [],
"webSearchResults": []
}

Step 3: Get Consumer Details via External Validation (Mandatory)

Endpoint: POST /api/v1/individual/:id/external-validation

Execute external client validation to retrieve consumer details from credit bureaus. This provides KYC (Know Your Customer) results and consumer information.

Path Parameters:

  • id (string, required): The individual UUID from Step 1

Request Body: Optional validation parameters. If not provided, uses data from the individual record.

Response: Returns consumer details, KYC results, and employment history.

{
"consumerDetail": {
"FirstName": "JOHN",
"Surname": "DOE",
"IDNo": 7510315000081,
"BirthDate": "1975-10-31T00:00:00+02:00",
"Gender": "Male",
"EmailAddress": "johndoe@gmail.com"
},
"kycResult": {
"IDStatusDesc": "ID Validated On Bureau Data",
"KYCStatusDesc": "No Match Established Within Provided Parameters"
},
"consumerEmploymentHistory": []
}

Step 4: Review KYC, PEP & Sanctions Data (Mandatory)

Manual Review Process: Review the data returned from Steps 2 and 3, including:

  • AML screening results
  • KYC validation results
  • PEP (Politically Exposed Persons) status
  • Sanctions list matches

Endpoint: PATCH /api/v1/individual/:id/pep-sanctions-decision

Update the PEP and sanctions decision based on your review.

Path Parameters:

  • id (string, required): The individual UUID from Step 1

Request Body: See PEP & Sanctions Decision Request section below.

Response: Returns updated individual record.


Step 5: Upload Documents (Mandatory)

Endpoint: POST /api/v1/individual/:id/documents

Upload client documents. You can upload a single file and associate it with multiple document groups and types to save storage space.

Path Parameters:

  • id (string, required): The individual UUID from Step 1

Request: Multipart form data

  • file (binary, required): Document file to upload
  • documents (string, required): JSON string array of document group-type pairs
  • additionalFicaDoc (string, optional): Additional FICA document flag

Example documents field:

[
{"individualDocsID": 1, "IndividualDocTypesID": 1},
{"individualDocsID": 7, "IndividualDocTypesID": 19}
]

Response: Returns created document records with FICA document IDs.

{
"assignedGroups": [
{
"groupId": 1,
"types": [
{
"typeId": 1,
"ficaIndividualDocsID": 123
}
]
}
],
"documents": [],
"count": 2
}

Important:

  • Maximum file size: 10MB (default, configurable via MAX_FILESIZE_MB environment variable)
  • Supported formats: PDF, images (PNG, JPEG, JPG)
  • Each document pair creates a separate record pointing to the same uploaded file

Step 6: Document Management (Optional, then Mandatory Confirmation)

6a. View Uploaded Document (Optional)

Endpoint: GET /api/v1/individual/:id/documents/:ficaIndividualDocsID

Retrieve a document as a base64-encoded string.

Path Parameters:

  • id (string, required): The individual UUID
  • ficaIndividualDocsID (number, required): FICA Individual Document ID from Step 5 response

Response: Returns base64-encoded document content.

{
"ficaIndividualDocsID": 123,
"base64Content": "JVBERi0xLjQKJeLjz9MK...",
"mimeType": "application/pdf",
"filename": "document.pdf"
}

6b. Delete Document (Optional)

Endpoint: DELETE /api/v1/individual/:id/documents/:ficaIndividualDocsID

Delete an incorrectly uploaded document.

Path Parameters:

  • id (string, required): The individual UUID
  • ficaIndividualDocsID (number, required): FICA Individual Document ID to delete

Response: Returns deleted document information.

6c. Confirm Documents Uploaded (Mandatory)

Endpoint: PATCH /api/v1/individual/:id/confirm-docs

Confirm that all required documents have been uploaded and reviewed. This sets docsUploadedReviewed to true.

Path Parameters:

  • id (string, required): The individual UUID

Request Body:

{
"userUUID": "123e4567-e89b-12d3-a456-426614174000"
}

Response: Confirmation message and status.

{
"message": "Documents confirmed successfully",
"docsUploadedReviewed": true
}

Step 7: Update Onboarding Decision (Mandatory)

Endpoint: PATCH /api/v1/individual/:id/onboarding-decision

Determine the final onboarding decision: approve, decline, or refer the client for review.

Path Parameters:

  • id (string, required): The individual UUID

Request Body: See Onboarding Decision Request section below.

Decision Options:

  • Approved: Client is approved and onboarded
  • Declined: Client is declined
  • Refer: Client is referred to another admin for review (will return to this step)
  • In Progress: Decision is still pending

Response: Success message.

{
"message": "The client was successfully onboarded."
}

Note: If a client is referred, they will return to this step after review.


Step 8: Get PDF Report (Optional)

Endpoint: GET /api/v1/individual/:id/pdf-report

Retrieve the complete FICA application report as a PDF (base64-encoded).

Path Parameters:

  • id (string, required): The individual UUID

Response: Base64-encoded PDF content.

{
"base64Content": "JVBERi0xLjQKJeLjz9MKMSAwIG9iago8PC9UeXBlIC9DYXRhbG9nCi9QYWdlcyAyIDAgUgo+PgplbmRvYmoK...",
"mimeType": "application/pdf",
"filename": "fica-report-123e4567-e89b-12d3-a456-426614174000.pdf"
}

Endpoint Reference

Additional Endpoints

List Individuals with Pagination and Filters

Endpoint: GET /api/v1/individual

Retrieve a paginated list of individuals for the authenticated partner with optional filtering. This endpoint is useful for searching and browsing individual records.

Query Parameters:

Pagination:

  • take (number, optional): Number of records to return (default: 50, maximum: 100)
  • skip (number, optional): Number of records to skip for pagination (default: 0)

Filters (all optional, can be combined):

  • externalUserID (string): Filter by external user ID (partial match)
  • clientReference (string): Filter by client reference (partial match)
  • firstName (string): Filter by first name (partial match)
  • lastName (string): Filter by last name (partial match)
  • ficaStatus (string): Filter by FICA status (partial match)
  • identificationNumber (string): Filter by identification number (partial match)
  • passportNumber (string): Filter by passport number (partial match)
  • riskDescription (string): Filter by risk description (partial match)
  • approvalDate (string, ISO date): Filter by approval date (matches entire day)
  • lastUpdated (string, ISO date): Filter by last updated date (matches entire day)
  • nextFicaReviewDate (string, ISO date): Filter by next FICA review date (matches entire day)

Response: Returns paginated list with count.

{
"data": [
{
"ficaIndividualGUID": "123e4567-e89b-12d3-a456-426614174000",
"externalUserID": "EXT-12345",
"clientReference": "REF123456",
"firstName": "John",
"lastName": "Doe",
"ficaStatus": "Approved",
"identificationNumber": "7510315073000",
"passportNumber": "A12345678",
"riskDescription": "Low Risk",
"approvalDate": "2025-12-01T00:00:00.000Z",
"approvedBy": "John Admin",
"lastUpdated": "2025-12-01T10:30:00.000Z",
"nextFicaReviewDate": "2026-12-01T00:00:00.000Z"
}
],
"count": 150,
"take": 50,
"skip": 0
}

Example Requests:

# Get first 50 individuals
GET /api/v1/individual?take=50&skip=0

# Search by first name
GET /api/v1/individual?firstName=John

# Filter by status and risk
GET /api/v1/individual?ficaStatus=Approved&riskDescription=Low Risk

# Filter by approval date
GET /api/v1/individual?approvalDate=2025-12-01T00:00:00.000Z

# Combined filters with pagination
GET /api/v1/individual?firstName=John&lastName=Doe&take=100&skip=0

Important Notes:

  • Maximum 100 results per page (enforced automatically)
  • Text filters use partial matching (contains)
  • Date filters match the entire day (00:00:00 to 23:59:59)
  • Results are ordered by lastUpdated date (descending)
  • Only returns individuals for the authenticated partner
  • All filters are optional and can be combined

Get Individual Details

Endpoint: GET /api/v1/individual/:id

Retrieve individual client details by UUID.

Path Parameters:

  • id (string, required): The individual UUID

Response: Complete individual record data.

Update Individual Details

Endpoint: PATCH /api/v1/individual/:id

Update individual client information.

Path Parameters:

  • id (string, required): The individual UUID

Request Body: See Update Individual Request section below.


Request/Response Examples

Create Individual Request

{
"externalSystemId": "EXT-12345",
"clientRef": "REF123456",
"firstName": "John",
"lastName": "Doe",
"clientEmail": "john.doe@example.com",
"telNumber": "+27123456789",
"userID": "123e4567-e89b-12d3-a456-426614174000",
"idNumber": "7510315073000",
"passportNumber": "A12345678",
"taxNumber": "1234567890",
"addressLineOne": "123 Main Street",
"addressLineTwo": "Apt 4B",
"townCity": "Cape Town",
"zipCode": "8001",
"employmentStatus": 5,
"occupation": "Software Engineer",
"employmentIndustry": 1,
"employerName": "Tech Corp",
"employerIndustry": "Technology",
"transactionFrequency": 1,
"transactionType": 31,
"transactionFundingSource": 32,
"transactionSourceWealth": 8,
"sourceFundingDescription": "Salary",
"sourceWealthDescription": "Savings",
"additionalVerification": false,
"additionalVerificationReason": null,
"transactionConsistent": "true",
"transactionInconsistantReason": null,
"customerPermission": true,
"partnerID": "889912d3-xxxx-xxxx-xxx-b77bb61231c1",
"countryResidence": 2,
"passportCountry": 0,
"addressCountry": 0,
"clientFaceToFace": true,
"clientSACitizen": true,
"customQuestions": {}
}

List Individuals Request Examples

Basic pagination:

GET /api/v1/individual?take=50&skip=0

Filter by name:

GET /api/v1/individual?firstName=John&lastName=Doe

Filter by status and risk:

GET /api/v1/individual?ficaStatus=Approved&riskDescription=Low Risk

Filter by date:

GET /api/v1/individual?approvalDate=2025-12-01T00:00:00.000Z

Combined filters with pagination:

GET /api/v1/individual?externalUserID=EXT-123&ficaStatus=Approved&take=100&skip=50

Update Individual Request

{
"firstName": "John",
"lastName": "Doe",
"clientEmail": "john.doe@example.com",
"clientPhone": "+27123456789",
"externalSystemId": "EXT-12345"
}

External Validation Request (Optional)

{
"identificationNumber": "0101010000081",
"passportNumber": "A12345678",
"firstName": "John",
"lastName": "Doe",
"residentialLine1": "123 Main Street",
"residentialLine2": "Apt 4B",
"residentialLine3": "Suburb",
"residentialZIPCode": "2000"
}

PEP & Sanctions Decision Request

{
"pepConfirmReviewed": true,
"adverseSearchKYC": false,
"clientForeignOfficial": false,
"clientForeignOfficialType": null,
"userID": "123e4567-e89b-12d3-a456-426614174000",
"partnerID": "123e4567-e89b-12d3-a456-426614174001"
}

Field Descriptions:

  • pepConfirmReviewed (boolean, required): Confirms PEP and sanctions have been reviewed
  • adverseSearchKYC (boolean, required): Are there adverse search results?
  • clientForeignOfficial (boolean, required): Is the client a foreign official?
  • clientForeignOfficialType (number, optional): Required if clientForeignOfficial is true
  • userID (UUID, required): UUID of the user making the decision
  • partnerID (UUID, required): UUID of the partner company

Document Upload Request (Multipart Form Data)

Form Fields:

  • file: Binary file (PDF, PNG, JPEG, JPG)
  • documents: JSON string: [{"individualDocsID": 1, "IndividualDocTypesID": 1}]
  • additionalFicaDoc: Optional string (e.g., "false")

cURL Example:

curl -X POST "https://sandboxapi.efica.co.za/api/v1/individual/123e4567-e89b-12d3-a456-426614174000/documents" \
-H "Authorization: Bearer <your-token>" \
-F "file=@/path/to/document.pdf" \
-F "documents=[{\"individualDocsID\": 1, \"IndividualDocTypesID\": 1}]" \
-F "additionalFicaDoc=false"

Confirm Documents Request

{
"userUUID": "123e4567-e89b-12d3-a456-426614174000"
}

Onboarding Decision Request

{
"onboardingDecision": "Approved",
"additionalComments": "All checks passed",
"nextFicaReviewDate": "2025-12-02T22:00:00.000Z",
"userID": "123e4567-e89b-12d3-a456-426614174000",
"partnerID": "123e4567-e89b-12d3-a456-426614174000"
}

Decision Values:

  • "Approved": Client approved
  • "Declined": Client declined
  • "Refer": Referred for review
  • "In Progress": Decision pending

Error Handling

Common HTTP Status Codes

Status CodeDescriptionCommon Causes
200SuccessRequest completed successfully
201CreatedResource created successfully
400Bad RequestInvalid request data, validation failed, file too large
401UnauthorizedMissing or invalid OAuth2 token
404Not FoundIndividual or document not found
500Internal Server ErrorServer error, external service failure

Error Response Format

{
"statusCode": 400,
"message": "Bad Request",
"error": "Validation failed"
}

Common Error Scenarios

1. Insufficient Balance (Step 1)

If your account has insufficient balance, the individual record will not be created. Check your account balance before attempting to create records.

2. File Upload Errors

File Too Large:

{
"status": 400,
"error": "File size (52428800 bytes) exceeds the maximum allowed size of 10MB"
}

No File Uploaded:

{
"status": 400,
"error": "No file uploaded. Please ensure you are sending a file with the field name \"file\"."
}

3. Invalid Document JSON

{
"status": 400,
"error": "Invalid JSON format for documents field",
"details": "Unexpected token..."
}

4. Missing Required Fields

{
"statusCode": 400,
"message": "Bad Request",
"error": "Validation failed"
}

5. Individual Not Found

{
"statusCode": 404,
"message": "Individual not found"
}

Error Handling Best Practices

  1. Always check response status codes before processing responses
  2. Implement retry logic for 500 errors (with exponential backoff)
  3. Validate file sizes before upload
  4. Handle insufficient balance gracefully in Step 1
  5. Log error responses for debugging
  6. Display user-friendly error messages based on status codes

Best Practices

1. Workflow Adherence

  • Follow the workflow sequence: Steps must be completed in order
  • Don't skip mandatory steps: All mandatory steps must be completed
  • Store the individual UUID: Save the id from Step 1 for all subsequent calls

2. Error Handling

  • Check account balance before Step 1
  • Implement proper error handling for all API calls
  • Retry failed requests where appropriate (500 errors)
  • Validate data before sending requests

3. Document Management

  • Upload documents in correct format: PDF, PNG, JPEG, JPG
  • Respect file size limits: Default 10MB, check configuration
  • Use document groups efficiently: One file can serve multiple document types
  • Verify uploads: Use GET endpoint to confirm document was uploaded correctly

4. Security

  • Never expose OAuth2 tokens: Store securely, never in client-side code
  • Use HTTPS: Always use encrypted connections
  • Validate responses: Don't trust client-side validation alone
  • Implement token refresh: Handle token expiration gracefully

5. Performance

  • Batch operations where possible: Upload multiple document types with one file
  • Cache individual UUIDs: Store locally to avoid unnecessary GET requests
  • Implement request timeouts: Prevent hanging requests
  • Use async/await: Handle asynchronous operations properly

6. Testing

  • Test in sandbox first: Always test in sandbox environment before production
  • Test error scenarios: Test insufficient balance, invalid data, etc.
  • Test file uploads: Verify different file types and sizes
  • Test workflow completion: Ensure entire workflow can be completed

7. Data Management

  • Store individual UUIDs: Keep track of created individual records
  • Store document IDs: Save ficaIndividualDocsID values for document operations
  • Log important events: Track workflow progress for debugging
  • Handle referrals: Implement logic to handle referred clients returning to Step 7

8. List and Search Operations

  • Use pagination efficiently: Request only the number of records you need (max 100 per page)
  • Combine filters: Use multiple filters together to narrow down results
  • Cache search results: Store frequently accessed individual GUIDs locally
  • Handle large result sets: Use skip parameter to paginate through all results
  • Date filtering: When filtering by dates, the API matches the entire day, so you don't need to specify exact times

Complete Workflow Example

List Individuals Example

Here's an example of listing and searching individuals:

// List all individuals (first page)
const listResponse = await fetch('https://sandboxapi.efica.co.za/api/v1/individual?take=50&skip=0', {
headers: { 'Authorization': `Bearer ${token}` }
});
const listData = await listResponse.json();
console.log(`Found ${listData.count} individuals, showing ${listData.data.length}`);

// Search by name
const searchResponse = await fetch('https://sandboxapi.efica.co.za/api/v1/individual?firstName=John&lastName=Doe', {
headers: { 'Authorization': `Bearer ${token}` }
});
const searchData = await searchResponse.json();

// Filter by status and risk
const filterResponse = await fetch('https://sandboxapi.efica.co.za/api/v1/individual?ficaStatus=Approved&riskDescription=Low Risk&take=100', {
headers: { 'Authorization': `Bearer ${token}` }
});
const filterData = await filterResponse.json();

// Paginate through all results
let allIndividuals = [];
let skip = 0;
const pageSize = 100;

do {
const pageResponse = await fetch(`https://sandboxapi.efica.co.za/api/v1/individual?take=${pageSize}&skip=${skip}`, {
headers: { 'Authorization': `Bearer ${token}` }
});
const pageData = await pageResponse.json();
allIndividuals = allIndividuals.concat(pageData.data);
skip += pageSize;
} while (allIndividuals.length < pageData.count);

Complete Onboarding Workflow Example

Here's a complete example of implementing the full workflow:

// Step 1: Create Individual
const createResponse = await fetch('https://sandboxapi.efica.co.za/api/v1/individual', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(individualData)
});
const { id } = await createResponse.json();

// Step 2: AML Screening
await fetch(`https://sandboxapi.efica.co.za/api/v1/individual/${id}/aml-screening`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${token}` }
});

// Step 3: External Validation
const validationResponse = await fetch(`https://sandboxapi.efica.co.za/api/v1/individual/${id}/external-validation`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(validationData)
});
const validationResults = await validationResponse.json();

// Step 4: Review data, then update PEP & Sanctions Decision
await fetch(`https://sandboxapi.efica.co.za/api/v1/individual/${id}/pep-sanctions-decision`, {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(pepSanctionsData)
});

// Step 5: Upload Documents
const formData = new FormData();
formData.append('file', fileBlob);
formData.append('documents', JSON.stringify([
{ individualDocsID: 1, IndividualDocTypesID: 1 }
]));
const uploadResponse = await fetch(`https://sandboxapi.efica.co.za/api/v1/individual/${id}/documents`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${token}` },
body: formData
});
const { documents } = await uploadResponse.json();

// Step 6: Confirm Documents
await fetch(`https://sandboxapi.efica.co.za/api/v1/individual/${id}/confirm-docs`, {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ userUUID: userId })
});

// Step 7: Onboarding Decision
await fetch(`https://sandboxapi.efica.co.za/api/v1/individual/${id}/onboarding-decision`, {
method: 'PATCH',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
onboardingDecision: 'Approved',
userID: userId,
partnerID: partnerId
})
});

// Step 8: Get PDF Report (Optional)
const pdfResponse = await fetch(`https://sandboxapi.efica.co.za/api/v1/individual/${id}/pdf-report`, {
headers: { 'Authorization': `Bearer ${token}` }
});
const pdfData = await pdfResponse.json();

Support

For additional support or questions:


Last Updated: 20 January 2026