# Login Source: https://docs.fincode.technology/api/auth/login PUT /securitymanagement/login Authenticate users and obtain access tokens for API requests Authenticate users with email and password to obtain JWT access and refresh tokens. This endpoint supports all user roles: MANAGER, AGENT, CASHIER, and CUSTOMER, etc. ## Request Headers   Must be `application/json`   Platform identifier. Use `fincode`   Unique request identifier. Use `200` ## Request Body     User's email address registered in the system     User's password (minimum 8 characters) ## Code Examples ```bash cURL theme={null} curl -X PUT "https://{your-domain}.fincode.software/api/v6/services/securitymanagement/login" \ -H "Content-Type: application/json" \ -H "platform: fincode" \ -H "uuid: 200" \ -d '{ "email": "manager@yourcompany.com", "currentPassword": "Password@1" }' ``` ```java Java theme={null} import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import com.google.gson.Gson; import com.google.gson.JsonObject; public class FinCodeLogin { public static class LoginRequest { public String email; public String currentPassword; public LoginRequest(String email, String password) { this.email = email; this.currentPassword = password; } } public static class LoginResponse { public String access_token; public int expires_in; public String refresh_token; public User user; public static class User { public String id; public String email; public String role; public String tenant_id; public String[] permissions; } } public static LoginResponse login(String email, String password) throws Exception { HttpClient client = HttpClient.newHttpClient(); Gson gson = new Gson(); LoginRequest loginRequest = new LoginRequest(email, password); String requestBody = gson.toJson(loginRequest); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://{your-domain}.fincode.software/api/v6/services/securitymanagement/login")) .header("Content-Type", "application/json") .header("platform", "fincode") .header("uuid", "200") .PUT(HttpRequest.BodyPublishers.ofString(requestBody)) .build(); HttpResponse response = client.send( request, HttpResponse.BodyHandlers.ofString() ); if (response.statusCode() == 200) { LoginResponse loginResponse = gson.fromJson(response.body(), LoginResponse.class); System.out.println("Login successful!"); System.out.println("User Role: " + loginResponse.user.role); System.out.println("Access Token: " + loginResponse.access_token); return loginResponse; } else { throw new Exception("Login failed: " + response.body()); } } public static void main(String[] args) { try { LoginResponse response = login("manager@yourcompany.com", "Password@1"); String accessToken = response.access_token; } catch (Exception e) { e.printStackTrace(); } } } ``` *** ## Error Handling **Cause**: Email or password is incorrect **Solution**: * Verify email address is correct * Check password is entered correctly * Use password reset if forgotten * Contact support if issue persists **Cause**: Multiple failed login attempts **Solution**: * Wait for the lockout period to expire * Contact your administrator to unlock the account * Use the "Forgot Password" flow to reset password **Cause**: Email address not registered in the system **Solution**: * Verify the email address * Check if the user exists in your tenant * Contact administrator to create the user account *** ## Best Practices * Store tokens securely (encrypted storage) * Use environment variables for tokens * Clear tokens on logout * Implement automatic token refresh * Refresh before expiration (5 min buffer) * Implement retry logic * User-friendly messages * CSRF protection * Set secure cookie flags *** ## Testing in Sandbox Use these test credentials in your sandbox environment: ```javascript theme={null} const testCredentials = { manager: { email: "manager@sandbox.fincode.software", password: "Password@1", }, agent: { email: "agent@sandbox.fincode.software", password: "Password@1", }, cashier: { email: "cashier@sandbox.fincode.software", password: "Password@1", }, customer: { email: "customer@sandbox.fincode.software", password: "Password@1", }, }; ``` These credentials only work in sandbox. Never use test credentials in production. # Logout Source: https://docs.fincode.technology/api/auth/logout PUT /securitymanagement/logout Invalidate the current user session by revoking the refresh token and access token. Invalidate the current user session by revoking both the access token and the refresh token. After a successful logout, the user must perform a full login with email and password to regain access. ## Request Headers Must be `application/json` Platform identifier. Use `fincode` Unique request identifier. Use `200` The JWT access token of the authenticated user. ## Code Examples ```javascript Node.js theme={null} const axios = require("axios"); async function logout(refreshToken) { try { const response = await axios.put( "https://{your-domain}.fincode.software/api/v6/services/securitymanagement/logout", { refresh_token: refreshToken, }, { headers: { "Content-Type": "application/json", platform: "fincode", uuid: "200", }, } ); console.log("Logout successful:", response.data.message); return response.data; } catch (error) { console.error("Logout failed:", error.response?.data || error.message); throw error; } } // Example Usage const currentRefreshToken = "eyJhbGciOiJ..."; logout(currentRefreshToken); ``` ```bash cURL theme={null} curl -X PUT "https://{your-domain}.fincode.software/api/v6/services/securitymanagement/logout" \ -H "Content-Type: application/json" \ -H "platform: fincode" \ -H "uuid: 200" \ -d '{ "refresh_token": "YOUR_CURRENT_REFRESH_TOKEN" }' ``` # Refresh Token Source: https://docs.fincode.technology/api/auth/refresh-token PUT /securitymanagement/refresh-token Obtain a new access token and refresh token using a valid refresh token. Use a valid refresh token to obtain a new pair of JWT access and refresh tokens without requiring the user to re-authenticate with email and password. This is essential for maintaining a long-lived user session. ## Request Headers     Must be `application/json`     Platform identifier. Use `fincode`     Unique request identifier. Use `200` ## Request Body The refresh token obtained from the `/login` or previous `/refresh-token` response. ## Code Examples ```bash cURL theme={null} curl -X PUT "https://{your-domain}.fincode.software/api/v6/services/securitymanagement/refresh-token" \   -H "Content-Type: application/json" \   -H "platform: fincode" \   -H "uuid: 200" \   -d '{     "refresh_token": "YOUR_VALID_REFRESH_TOKEN_HERE"   }' ``` *** * Prompt the user to log in again using email and password. * Check the server logs to confirm token revocation status. * Treat as a security breach. Force the user to log in again. * Check if your system correctly overwrites the old refresh token with the new one. # API Reference Source: https://docs.fincode.technology/api/authentication Complete API documentation for FinCode platform - Authentication, Remittance, Lending, and Investment endpoints. Our REST API provides programmatic access to all FinCode services including remittance, digital lending, and investment operations. All API endpoints require authentication using JWT tokens. Make sure you've completed the [authentication setup](/authentication) before making API calls. *** ## Base URLs Your API base URL depends on your tenant domain and environment: ```bash Sandbox theme={null} https://{domain}.fincode.software/api/v6/services/ ``` ```bash Production theme={null} https://{domain}.fincode.tech/api/v6/services/ ``` Always test your integration thoroughly in the sandbox environment before deploying to production. *** ## API Architecture The FinCode API is organized into service-based endpoints following a RESTful architecture: ``` /api/v6/services/{service-name}/{resource} ``` ### Service Categories User authentication, token management, and session handling Remittance, and virtual wallet transaction processing KYC/AML verification, sanctions screening, and regulatory compliance Analytics, transaction reports, and business intelligence Commission management, partner payouts, and revenue distribution Create and manage managers, agents, cashiers, and customers *** ## Authentication All API requests must include authentication headers otherwise stated: ### Required Headers ```javascript theme={null} { "X-Auth-Token": "your_jwt_access_token", "Content-Type": "application/json", "platform": "fincode", "uuid": "200" } ``` ### Example Authenticated Request ```javascript theme={null} const axios = require('axios'); const response = await axios.get( 'https://your-company.fincode.software/api/v6/services/admin/organisation-preference-management/fetch-organisation-preference', { headers: { 'X-Auth-Token': process.env.JWT_ACCESS_TOKEN, 'Content-Type': 'application/json', platform: 'fincode', uuid: '200', }, } ); ``` Store your JWT tokens securely and implement automatic token refresh to maintain uninterrupted API access. *** ## Request & Response Format ### Standard Request Structure POST and PUT requests send a JSON body directly. There is no envelope wrapper — pass the fields the endpoint expects at the top level. ### Standard Response Structure All responses use a consistent `ResultWrapper` envelope: ```json theme={null} { "status": "SUCCESS", "message": "Operation completed successfully", "responseCode": 0, "errorCode": "0", "data": { // Response payload (structure varies per endpoint) } } ``` | Field | Type | Description | | - | - | - | | `status` | String | See status values below | | `message` | String | Human-readable description of the result | | `responseCode` | Integer | Numeric result code — `0` for success, `-1` for failure | | `errorCode` | String | String representation of the result code — `"0"` for success, `"-1"` for failure | | `data` | Object | Response payload — structure varies per endpoint | The `status` field is always one of: | Value | Meaning | | - | - | | `SUCCESS` | Request completed successfully | | `FAILED` | Request failed — check `message` for the reason | | `ERROR` | An error occurred | | `PROCESSING` | Request accepted and still being processed | | `PENDING` | Awaiting further action | | `PAID` | Payment completed | | `CANCEL` | Request was cancelled | | `IGNORE` | Request was ignored | Failed responses follow the same envelope: ```json theme={null} { "status": "FAILED", "message": "Detailed error description", "responseCode": -1, "errorCode": "-1" } ``` *** ## Error Handling Most API endpoints return HTTP 200 regardless of outcome and communicate success or failure through the `status` field in the response body. However, some endpoints — and Spring Security — will return HTTP-level error codes in certain situations. | HTTP Status | When it occurs | | - | - | | `401` | Missing or invalid JWT token — returned by Spring Security before the request reaches the controller | | `400` | Bad request — returned by some endpoints on invalid input | | `500` | Internal server error — returned by some endpoints on unexpected failures | Always handle both layers — the HTTP status code and the `status` field in the response body. ### Error Handling Example ```javascript theme={null} try { const response = await axios.post(url, body, { headers }); const result = response.data; if (result.status === 'FAILED' || result.status === 'ERROR') { console.error('Request failed:', result.message); throw new Error(result.message); } // Safe to use result.data return result.data; } catch (error) { if (error.response) { switch (error.response.status) { case 401: // Token missing or expired — refresh and retry await refreshToken(); return makeApiCall(); case 400: console.error('Bad request:', error.response.data); throw error; case 500: console.error('Server error:', error.response.data); throw error; default: console.error('Unexpected error:', error.response.data); throw error; } } throw error; } ``` *** ## Webhooks FinCode can notify your application of events via webhooks. Configure webhook endpoints in your dashboard. ### Webhook Events | Event | Description | | - | - | | `TRANSACTION_STATUS` | Fired when a transaction reaches a terminal status (PAID, FAILED, CANCELLED) | | `COMPLIANCE_RISK_PROFILE_UPDATED` | Fired after an eKYC result or AML screening updates a customer's compliance profile | ### Webhook Payload Example ```json theme={null} { "event-type": "TRANSACTION_STATUS", "data": { // Event-specific payload } } ``` Register a callback URL for each event type you want to receive in your pay centre configuration. [Learn more about webhooks →](/api/webhooks) *** ## SDKs & Libraries Official SDKs are currently in development. We'll support JavaScript/TypeScript, Python, PHP, and Ruby in the near future. For now, you can use standard HTTP clients like `axios`, `fetch`, or `requests` to integrate with our API. ### Coming Soon Node.js and browser support with full TypeScript definitions Pythonic API with async/await support PSR-compliant library for PHP 7.4+ Ruby gem with Rails integration *** ## Testing & Sandbox Use the sandbox environment for testing without affecting production data: * **URL**: `https://{domain}.fincode.software/api/v6/services/` * **Data**: All transactions are simulated * **Webhooks**: Webhook events are generated but not processed ### Test Data Use these test credentials in sandbox: **Test Bank Account** ```json theme={null} { "account_number": "8883633074", "bank_code": "044", "account_name": "VICTOR ADEBIYI" } ``` **Test Card** ```json theme={null} { "card_number": "4111 1111 1111 1111", "expiry": "12/27", "cvv": "123" } ``` ## Support & Resources Real-time system status Technical support team Code examples & samples # Activate AML Rule Source: https://docs.fincode.technology/api/ciam/activate-aml-rule PUT /admin/compliance/activate-aml-rule/{id} Activates a specific AML rule. # Activate User Account Source: https://docs.fincode.technology/api/ciam/activate-user GET /usermanagement/activate-user-account/{id} Activates a user account by ID. # Add Default Charge Source: https://docs.fincode.technology/api/ciam/add-default-charge POST /admin/fee-management/add-default-charge Adds a default charge. # Add KYC Rule Source: https://docs.fincode.technology/api/ciam/add-kyc-rule POST /admin/compliance/add-kyc-rule Adds a new KYC rule. # Submit KYC Documents Source: https://docs.fincode.technology/api/ciam/attach-documents POST /documentmanagement/attach-documents Upload identity and compliance documents for a customer. Attach one or more identity or compliance documents to a customer record. Documents are matched to outstanding KYC rules via `associatedRuleId`. ## Request Headers The **JWT Access Token** of the authenticated user. Platform identifier. Use `fincode`. Unique request identifier. ## Request Body The customer's alphanumeric customer code (e.g. `VJJGVE`). Not the userId UUID. List of documents to attach. Each item has the following fields: The document image encoded as a **data URI**. Must be in the format: ``` data:image/jpeg;base64, ``` Raw base64 (without the `data:image/...;base64,` prefix) is not accepted and will cause a server error. Supported MIME types: `image/jpeg`, `image/png`, `application/pdf`. File name including extension (e.g. `passport_front.jpg`). The extension must be present — it is used to determine the file type. Document type. One of: | Value | Description | | - | - | | `PASSPORT` | Passport | | `NATIONAL_ID_CARD` | National identity card | | `DRIVING_LICENSE` | Driving licence | | `VOTE_CARD` | Voter ID / voter card | | `ADDRESS_PROOF` | Proof of address | | `SOURCE_OF_INCOME_PROOF` | Source of income proof | | `EKYC_FACE_PHOTO` | eKYC face photo (selfie) | | `EKYC_FACE_VIDEO` | eKYC face video | | `BUSINESS_REGISTRATION` | Business registration document | | `OTHER_OFFICIAL_DOCUMENT` | Other official document | | `OTHER` | Other | The `associatedRuleId` from the [Awaiting Compliance Requirements](/api/ciam/awaiting-compliance-requirements) response. Links this document to the outstanding KYC rule. Required when submitting a document against a specific rule — if omitted, the document is uploaded but does not automatically close any open requirement. Use the `associatedRuleId` field from the awaiting compliance item, **not** the `customer-kyc-record-id`. They are different values. Document number (e.g. passport number). ISO 3166-1 alpha-3 country code of the issuing country (e.g. `GBR`). Issue date in ISO format (e.g. `2015-06-01`). Expiry date in ISO format (e.g. `2030-06-01`). Date of birth as shown on the document, in ISO format (e.g. `1990-05-15`). ## Code Example ```bash cURL theme={null} curl -X POST 'https://{your-domain}.fincode.software/api/v6/services/documentmanagement/attach-documents' \ --header 'X-Auth-Token: YOUR_TOKEN' \ --header 'Content-Type: application/json' \ --header 'platform: fincode' \ --header 'uuid: 200' \ --data '{ "customerCode": "VJJGVE", "attachedDocument": [ { "file_base64": "data:image/jpeg;base64,/9j/4AAQSkZJRgAB...", "name": "passport_front.jpg", "idType": "PASSPORT", "associatedRuleId": "rule-uuid-from-awaiting-compliance", "issueNo": "123456789", "issueCountry": "GBR", "issueDate": "2015-06-01", "expiryDate": "2030-06-01", "dob": "1990-05-15" } ] }' ``` # Awaiting Compliance Requirements Source: https://docs.fincode.technology/api/ciam/awaiting-compliance-requirements GET /compliance/awaiting-compliance-requirements Returns the outstanding KYC requirements for a customer. Returns the list of pending compliance actions the customer must complete before they are fully verified. Poll this endpoint after registration to know what the customer still needs to do. ## Request Headers The **JWT Access Token** of the authenticated user (agent, cashier, or the customer themselves). The `userId` UUID of the customer whose requirements you want to check. Required when the token belongs to an agent or cashier — without it, the endpoint returns requirements for the token holder, not the customer. Must be the customer's **userId UUID** (e.g. `550e8400-e29b-41d4-a716-446655440000`), not their customer code (e.g. `VJJGVE`). Platform identifier. Use `fincode`. Unique request identifier. ## Query Parameters Alternative way to specify the target customer — the customer's userId UUID. Either this or `X-CUSTOMER-ID` can be used; `X-CUSTOMER-ID` takes precedence if both are provided. ## Response `SUCCESS` or `FAILED`. Inner status string — `Success` when the call completes. List of pending compliance actions the customer must complete. Empty array means the customer is fully compliant. ID of this compliance record. Pass as the path parameter when calling Initiate Compliance Action. The rule ID to include in `attachedDocument[].associatedRuleId` when uploading documents. The type of action required. Possible values: `VERIFY_ACCOUNT_VIA_EMAIL`, `VERIFY_ACCOUNT_VIA_PHONE_NUMBER`, `VERIFY_ACCOUNT_VIA_EKYC`, `VERIFY_ACCOUNT_VIA_EKYC_FACE_PHOTO`, `VERIFY_ACCOUNT_VIA_EKYC_FACE_VIDEO`, `VERIFY_ACCOUNT_VIA_IDENTIFICATION_DOCUMENT`, `CUSTOMER_RISK_ASSESSMENT`, `THRESHOLD_IDENTIFICATION`, `THRESHOLD_LIMIT`, `THRESHOLD_LIMIT_RECEIVING_AMOUNT`, `THRESHOLD_COUNT_TRANSACTION`, `LINKED_TRANSACTION`, `OTHER`. See Action Types below. How this requirement restricts the customer. Values: `BLOCK` (customer cannot proceed until resolved), `WARN` (customer can proceed but transaction goes to compliance), `ALLOW` (customer can proceed if within range). Human-readable instruction to display to the customer. The business rule number that triggered this requirement. The screening type. Values: `AML`, `CRA`, `KYC`, `EDD`, `NONE_APPLICABLE`. `true` if this action requires a document to be uploaded. List of acceptable document types. Each item has `docIdType` and `docTypeCommonName`. Minimum number of documents from `acceptableDocTypes` that must be submitted. The eKYC provider integration ID. Present when `actionType` is `VERIFY_ACCOUNT_VIA_EKYC`. The eKYC provider code — e.g. `SHUFTI_PRO`, `SEON_IDV`, `SUMSUB`. Dynamic form ID for CRA actions. List of dynamic field IDs associated with the CRA form. The type of data collection form required. Lower bound of the transaction amount range that triggered this rule. Upper bound of the transaction amount range that triggered this rule. The sending amount at the time this rule was evaluated. The compliance result. Values: `PASS`, `WARNING`, `FAIL`. Who this compliance action applies to. Values: `CUSTOMER`, `RECEIVER`. Legacy field — the document ID type from the first acceptable doc type. Legacy field — the common name of the first acceptable doc type. Legacy field — single `DocIdTypeDTO` from the first acceptable doc type. ## Action Types | actionType | What it means | What to do | | - | - | - | | `VERIFY_ACCOUNT_VIA_EMAIL` | Customer must verify their email | Platform sends a verification email. If `doNotForwardEmailVerification` is enabled, call [Verify Contact](/api/ciam/verify-contact) with `type=EMAIL` after verifying on your side. | | `VERIFY_ACCOUNT_VIA_PHONE_NUMBER` | Customer must verify their phone | Platform sends an OTP via SMS. If `doNotForwardPhoneVerification` is enabled, call [Verify Contact](/api/ciam/verify-contact) with `type=PHONE_NUMBER`. | | `CUSTOMER_RISK_ASSESSMENT` | Customer must fill a compliance risk assessment form | Call [Initiate Compliance Action](/api/ciam/initiate-compliance-action) to get the form, then submit via [Submit CRA](/api/ciam/submit-cra). | | `THRESHOLD_IDENTIFICATION` | Transaction amount threshold triggered — customer must upload an identity document (Passport, Address Proof, or ID) | Call [Initiate Compliance Action](/api/ciam/initiate-compliance-action), then [Submit KYC Documents](/api/ciam/attach-documents) with the `associatedRuleId`. | | `THRESHOLD_LIMIT` | Sending amount limit check | Transaction is blocked until the threshold condition is resolved by the compliance team. | | `THRESHOLD_LIMIT_RECEIVING_AMOUNT` | Receiving amount limit check | Transaction is blocked until the threshold condition is resolved by the compliance team. | | `THRESHOLD_COUNT_TRANSACTION` | Transaction count limit check | Transaction is blocked until the threshold condition is resolved. | | `LINKED_TRANSACTION` | Transaction matches a linked-transaction rule (country, name, DOB match) | Transaction is held pending manual review. | | `VERIFY_ACCOUNT_VIA_EKYC` | Customer must complete full eKYC identity verification | Call [Initiate External KYC Provider](/api/ciam/initiate-external-provider). | | `VERIFY_ACCOUNT_VIA_EKYC_FACE_PHOTO` | Customer must submit a live face photo | Call [Initiate External KYC Provider](/api/ciam/initiate-external-provider) and load the camera SDK. | | `VERIFY_ACCOUNT_VIA_EKYC_FACE_VIDEO` | Customer must record a live face video | Call [Initiate External KYC Provider](/api/ciam/initiate-external-provider) and load the video SDK. | | `VERIFY_ACCOUNT_VIA_IDENTIFICATION_DOCUMENT` | Customer must upload an identity document | Call [Initiate Compliance Action](/api/ciam/initiate-compliance-action), then [Submit KYC Documents](/api/ciam/attach-documents). | | `OTHER` | Catch-all action type | Follow the `customerInstruction` field. | ## Code Example ```bash cURL theme={null} curl -X GET 'https://{your-domain}.fincode.software/api/v6/services/compliance/awaiting-compliance-requirements' \ --header 'X-Auth-Token: YOUR_TOKEN' \ --header 'X-CUSTOMER-ID: 550e8400-e29b-41d4-a716-446655440000' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` # Awaiting Payments Source: https://docs.fincode.technology/api/ciam/awaiting-payments PUT /admin/payment-management/awaiting-payments Updates awaiting payments. # Change Password Source: https://docs.fincode.technology/api/ciam/change-password PUT /securitymanagement/change-password Changes the user password. # Pre-Transaction Compliance Checklist Source: https://docs.fincode.technology/api/ciam/compliance-checklist PUT /compliance/customer-compliance-checklist Returns the compliance checklist a customer must satisfy before a transaction can be booked. Call this before `create-transaction` to find out exactly what compliance actions are required for the given transaction parameters. The platform evaluates all applicable KYC rules and business transaction rules and returns a checklist of outstanding items. If `transactionQuote` is provided, AML checks are also included in the evaluation. All authenticated user types can call this endpoint. ## Request Headers JWT Access Token of the authenticated user. The customer's `userId` (UUID). Pass this when an agent or manager is checking on behalf of a customer. Platform identifier. Use `fincode`. Unique request identifier. ## Request Body The transaction parameters to evaluate compliance against. Which side of the transaction to evaluate. Use `PAYIN` when the customer is sending money. * `PAYIN` — evaluate rules on transaction creation * `PAYOUT` — evaluate rules on payout * `ACCOUNT_CREDITING` — evaluate rules on account credit The amount the sender intends to send. ISO 4217 currency code of the sending currency (e.g. `GBP`). ISO 3166-1 alpha-3 destination country code (e.g. `NGA`). Transaction type / delivery method (e.g. `ACCOUNTPAYMENT`, `MOBILE_MONEY`, `CASH_PICKUP`). ## Response `SUCCESS` or `FAILED`. List of compliance actions required before the transaction can proceed. An empty array means the customer is fully compliant and the transaction can be booked immediately. The type of action required. Possible values: `VERIFY_ACCOUNT_VIA_EMAIL`, `VERIFY_ACCOUNT_VIA_PHONE_NUMBER`, `VERIFY_ACCOUNT_VIA_EKYC`, `VERIFY_ACCOUNT_VIA_EKYC_FACE_PHOTO`, `VERIFY_ACCOUNT_VIA_EKYC_FACE_VIDEO`, `VERIFY_ACCOUNT_VIA_IDENTIFICATION_DOCUMENT`, `CUSTOMER_RISK_ASSESSMENT`, `THRESHOLD_IDENTIFICATION`, `THRESHOLD_LIMIT`, `THRESHOLD_LIMIT_RECEIVING_AMOUNT`, `THRESHOLD_COUNT_TRANSACTION`, `LINKED_TRANSACTION`, `OTHER`. The compliance rule ID. Pass this as `associatedRuleId` when submitting documents via `attach-documents`. The KYC record ID. Used as the path parameter when calling `initiate-compliance-action`. The business rule that triggered this requirement. How strictly this blocks the transaction. Values: `BLOCK` (hard block until resolved), `WARN` (allow but flag to compliance), `ALLOW` (allow if within range). Human-readable instruction to display to the customer. `true` if the action requires a document to be uploaded. List of acceptable document types for this requirement. Minimum number of documents from `acceptableDocTypes` that must be submitted. The screening type. Values: `AML`, `CRA`, `KYC`, `EDD`, `NONE_APPLICABLE`. The eKYC provider integration ID. Present when `actionType` is `VERIFY_ACCOUNT_VIA_EKYC`. The eKYC provider code — e.g. `SHUFTI_PRO`, `SEON_IDV`, `SUMSUB`. Dynamic form ID for CRA (Customer Risk Assessment) actions. The type of data collection form required. Lower bound of the transaction amount range that triggered this rule. Upper bound of the transaction amount range that triggered this rule. The sending amount at the time this rule was evaluated. The customer classification this rule applies to. Values: `INDIVIDUAL`, `COMPANY`. Who this compliance action applies to. Values: `CUSTOMER`, `RECEIVER`. The compliance result. Values: `PASS`, `WARNING`, `FAIL`. ## Code Example ```bash cURL theme={null} curl -X PUT 'https://{your-domain}.fincode.software/api/v6/services/compliance/customer-compliance-checklist' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'X-CUSTOMER-ID: 00000000-0000-0000-0000-000000000001' \ --header 'Content-Type: application/json' \ --header 'platform: fincode' \ --header 'uuid: 200' \ --data '{ "transactionQuote": { "direction": "PAYIN", "amountSend": 100.00, "sendingCurrencyCode": "GBP", "receivingCountryIso3Code": "NGA", "devliveryMethod": "ACCOUNTPAYMENT" } }' ``` ```javascript Node.js theme={null} const axios = require('axios'); async function getComplianceChecklist(accessToken, userId, quote) { const response = await axios.put( 'https://{your-domain}.fincode.software/api/v6/services/compliance/customer-compliance-checklist', { transactionQuote: quote }, { headers: { 'X-Auth-Token': accessToken, 'X-CUSTOMER-ID': userId, 'platform': 'fincode', 'uuid': '200', 'Content-Type': 'application/json', }, } ); const checklist = response.data.data.customerComplianceCheckList; if (checklist.length === 0) { console.log('Customer is compliant — transaction can proceed.'); } else { console.log(`${checklist.length} compliance action(s) required:`, checklist); } return checklist; } // Usage getComplianceChecklist('YOUR_TOKEN', '00000000-0000-0000-0000-000000000001', { direction: 'PAYIN', amountSend: 100.00, sendingCurrencyCode: 'GBP', receivingCountryIso3Code: 'NGA', devliveryMethod: 'ACCOUNTPAYMENT', }); ``` # Start/Continue Verification Source: https://docs.fincode.technology/api/ciam/continue-enrolment GET /admin/compliance/continue-enrolment Checks or triggers the next stage of external compliance screening for a customer, typically after a Customer Risk Assessment (CRA) form submission. This endpoint is crucial for initiating or checking the status of required **external compliance screenings** (e.g., identity verification, sanctions checks) after a customer has submitted their initial forms or documents. It confirms whether the external process has started and provides the necessary URL if user interaction is required. # List Attached Dynamic Forms Source: https://docs.fincode.technology/api/ciam/cra-forms GET /admin/compliance/list-attached-form Retrieves a list of required compliance forms or documents currently attached to the authenticated user's profile. Retrieves a list of specific compliance forms, or data requirements currently pending or attached to the user's profile. This is often used by agents or administrators to manage customer compliance requirements. # Create Connector Instance Source: https://docs.fincode.technology/api/ciam/create-connector-instance POST /admin/connector-management/create-connector-instance Creates a connector instance. # Create Customer Source: https://docs.fincode.technology/api/ciam/create-customer POST /usermanagement/register-customer Register a new customer account in the FinCode platform Create a new customer account with personal information and authentication credentials. Customers can access self-service features including sending remittances, applying for loans, and managing investments. ## Password Encryption **Security Requirement**: The `password` and `confirmPassword` fields can optionally be encrypted using RSA public key encryption before sending to the API. When registering customers, you can choose to encrypt password fields using the RSA public key provided on your dashboard. Encryption ensures data confidentiality during transmission. ### Customer Registration Flow The `payloadEncrypted` field determines how the system processes your payload: | Value | Description | | - | - | | `true` | Indicates payload is RSA-encrypted. The system will decrypt before processing. | | `false` | Indicates payload is sent as raw plaintext. Use only for testing or internal systems. | For production integrations, use `payloadEncrypted` with encrypted passwords to protect customer credentials. Learn how to encrypt passwords using RSA public key encryption with OAEP padding (SHA-256). ## Request Headers | Header | Type | Required | Description | | - | - | - | - | | `Content-Type` | string | Yes | Must be `application/json` | | `platform` | string | Yes | Platform identifier. Use `fincode` | | `uuid` | string | Yes | Unique request identifier. Use `200` | ## Code Examples ```javascript Node.js theme={null} const axios = require('axios'); const crypto = require('crypto'); // Encrypt password using RSA public key function encryptPassword(password, publicKeyBase64) { const publicKeyPem = `-----BEGIN PUBLIC KEY-----\n${publicKeyBase64}\n-----END PUBLIC KEY-----`; const encrypted = crypto.publicEncrypt( { key: publicKeyPem, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: 'sha256', }, Buffer.from(password, 'utf8') ); return encrypted.toString('base64'); } async function createCustomer(customerData, publicKey) { // Encrypt passwords before sending const encryptedPassword = encryptPassword(customerData.password, publicKey); try { const response = await axios.post( 'https://agent.fincode.software/api/v6/services/usermanagement/register-customer', { devicePlatform: customerData.devicePlatform, appVersion: customerData.appVersion, appId: customerData.appId, customerType: customerData.customerType, payloadEncrypted: true, // Required for encrypted data firstName: customerData.firstName, lastName: customerData.lastName, email: customerData.email, address: { street: customerData.address.street, city: customerData.address.city, state: customerData.address.state, postalCode: customerData.address.postalCode, country: customerData.address.country, }, dialingCode: customerData.dialingCode, phone: customerData.phone, dob: customerData.dob, password: encryptedPassword, confirmPassword: encryptedPassword, dynamicFields: customerData.dynamicFields || {}, }, { headers: { 'Content-Type': 'application/json', platform: 'fincode', uuid: '200', }, } ); console.log('Customer created successfully!'); console.log('Customer code:', response.data.customerCode); console.log('User ID:', response.data.userIdKey); return response.data; } catch (error) { console.error( 'Failed to create customer:', error.response?.data || error.message ); throw error; } } ``` ```bash cURL (Encrypted Password) theme={null} curl -X POST "https://agent.fincode.software/api/v6/services/usermanagement/register-customer" \ -H "Content-Type: application/json" \ -H "platform: fincode" \ -H "uuid: 200" \ -d '{ "devicePlatform": "Android", "appVersion": "1", "appId": "com.app.remit_junction", "customerType": "INDIVIDUAL", "customerRegistrationFlow": "EXTERNAL_CUSTOMER_SETUP_FLOW", "firstName": "John", "lastName": "Doe", "email": "john.doe@example.com", "dialingCode": "+44", "phone": "973 293 74813", "dob": "1990-05-15T00:00:00+01:00", "password": "O5ti8XI/pLYC27E+ehORvg2YplXqX3ckoS7Kzk9cEdtC+LSzVICID9c/Tzsi0V5dEVScmSb74/OwCjYEo1akURB+hD1fC5E/SHVEZIWMY6OKZjFqGx4fCd5gtS3z2kQsdWdm6rqd7144pZbB7PPzkK/I5kIM2TyzOlfMg4nMNNTbwowhzt1cn1YK9kGwkLQgdpSv1BNHkiSaXXl+I6FAqPEVt7leJGJ5njkv7abxkYpIB8JjDYGdQzBAzBXCRysBuJSrLVgU78eAqQ3OvVRzS5pvdFDPhWPaqvOt7Xz+NaH3P3X6JS7XF14h0+fll/rvYTg+OqPLu4yX68PaGf6gcg==", "confirmPassword": "O5ti8XI/pLYC27E+ehORvg2YplXqX3ckoS7Kzk9cEdtC+LSzVICID9c/Tzsi0V5dEVScmSb74/OwCjYEo1akURB+hD1fC5E/SHVEZIWMY6OKZjFqGx4fCd5gtS3z2kQsdWdm6rqd7144pZbB7PPzkK/I5kIM2TyzOlfMg4nMNNTbwowhzt1cn1YK9kGwkLQgdpSv1BNHkiSaXXl+I6FAqPEVt7leJGJ5njkv7abxkYpIB8JjDYGdQzBAzBXCRysBuJSrLVgU78eAqQ3OvVRzS5pvdFDPhWPaqvOt7Xz+NaH3P3X6JS7XF14h0+fll/rvYTg+OqPLu4yX68PaGf6gcg==", "address": { "address1": "123 High Street", "address2": "", "countryCommonName": "United Kingdom", "postcode": "SW1A 1AA", "countryIso3": "GBR" }, "dynamicFields": {} }' ``` For internal testing or development environments where encryption is not required: ```bash theme={null} curl -X POST "https://agent.fincode.software/api/v6/services/usermanagement/register-customer" \ -H "Content-Type: application/json" \ -H "platform: fincode" \ -H "uuid: 200" \ -d '{ "devicePlatform": "Android", "appVersion": "1", "appId": "com.app.remit_junction", "customerType": "INDIVIDUAL", "payloadEncrypted": false, "firstName": "John", "lastName": "Doe", "email": "john.doe+test@example.com", "dialingCode": "+44", "phone": "973 293 74813", "dob": "1990-05-15T00:00:00+01:00", "password": "SecurePass123!", "confirmPassword": "SecurePass123!", "address": { "address1": "123 High Street", "address2": "", "countryCommonName": "United Kingdom", "postcode": "SW1A 1AA", "countryIso3": "GBR" }, "dynamicFields": {} }' ``` Never use `payloadEncrypted: false` in production environments as it transmits passwords without encryption. ## Validation Rules * Must be a valid email format - Must be unique across all customers in the tenant - Cannot be changed after creation - Maximum length: 255 characters * Minimum 8 characters - At least one uppercase letter (A-Z) - At least one lowercase letter (a-z) - At least one number (0-9) - At least one special character (!@#\$%^&\*) - Cannot contain common words or patterns * Must be in international format with country code - Example: +447123456789 (UK), +12125551234 (US) - No spaces or special characters except leading + - Must be a valid phone number for the country * Customer must be at least 18 years old - Date of birth must be in ISO format (YYYY-MM-DD) - Cannot be a future date - Cannot be more than 120 years ago * First name: 2-50 characters - Last name: 2-50 characters - Only letters, spaces, hyphens, and apostrophes allowed - No numbers or special characters ## Related Endpoints Authenticate the newly created customer Upload verification documents for the customer # Create Transaction PIN Source: https://docs.fincode.technology/api/ciam/create-transaction-pin POST /usermanagement/create-transaction-pin Creates a transaction PIN for the user. # Create User PIN Source: https://docs.fincode.technology/api/ciam/create-user-pin POST /securitymanagement/create-user-pin Creates a login PIN for the user. # Get Customer By ID Source: https://docs.fincode.technology/api/ciam/customer-by-id GET /admin/customer-management/profile/{id} Fetches the full profile of a specific customer by their userId. Returns the full profile of a customer. The `{id}` path parameter is the customer's `userId` (UUID). Accessible by `MANAGER`, `AGENTS`, `BRANCH_ADMIN`, `CASHIER`, `CUSTOMER_SERVICE`, `COMPLIANCE_USER`, and `AUDITOR` roles. ## Path Parameters The customer's `userId` (UUID) — returned as `userIdKey` from the register-customer and list-customers endpoints. ## Request Headers JWT Access Token of an authenticated staff member. Platform identifier. Use `fincode`. Unique request identifier. ## Response `SUCCESS` or `FAILED`. Full customer profile. The customer's userId (UUID). The customer's short code. First name. Last name. Email address. Phone number. Customer type: `INDIVIDUAL` or `COMPANY`. Current account status. ## Code Example ```bash cURL theme={null} curl -X GET 'https://{your-domain}.fincode.software/api/v6/services/admin/customer-management/profile/{userId}' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` # Deactivate AML Rule Source: https://docs.fincode.technology/api/ciam/deactivate-aml-rule PUT /admin/compliance/deactivate-aml-rule/{id} Deactivates a specific AML rule. # Deactivate User Account Source: https://docs.fincode.technology/api/ciam/deactivate-user GET /usermanagement/deactivate-user-account/{id} Deactivates a user account by ID. # Delete API Connector Instance Source: https://docs.fincode.technology/api/ciam/delete-api-connector-instance DELETE /admin/connector-management/delete-api-connector-instance/{id} Deletes a connector instance. # Delete Customer Bank Details Source: https://docs.fincode.technology/api/ciam/delete-customer-bank-details DELETE /bankmanagement/delete-customer-bank-details/{account-owner-id}/{bank-detail-id} Removes a saved bank account from a customer profile. Deletes a specific saved bank account record for a customer. ## Path Parameters The internal Customer record `id` (UUID). This is the `id` field returned by customer management endpoints — **not** the customer code. The `id` of the bank detail record to delete (UUID), returned by the list bank details endpoint. ## Request Headers JWT Access Token of the authenticated user. Platform identifier. Use `fincode`. Unique request identifier. ## Code Example ```bash cURL theme={null} curl -X DELETE 'https://{your-domain}.fincode.software/api/v6/services/bankmanagement/delete-customer-bank-details/{account-owner-id}/{bank-detail-id}' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` # Documents Required For Transaction Source: https://docs.fincode.technology/api/ciam/documents-required-for-transaction POST /complaince/documents-required-for-transaction # Get Dynamic Fields Source: https://docs.fincode.technology/api/ciam/dynamic-fields GET /dynamicfields/dynamic-fields-group/{processGroupCode} Retrieves a set of dynamic input fields required for a specific process (e.g., creating a transaction). Retrieves the structured set of dynamic fields (forms, documents, or additional data) required for a specific business process, identified by the `{processGroupCode}` in the URL. This allows client applications to adapt their user interface to the requirements of the chosen transaction type or user state. # Dynamic Fields Group Source: https://docs.fincode.technology/api/ciam/dynamic-fields-group GET /dynamicfields/dynamic-fields-group/{groupName} Retrieves dynamic fields for a group. # Edit Employee Source: https://docs.fincode.technology/api/ciam/edit-employee PUT /admin/employee-management/edit-employee/{id} Updates employee details. # Edit KYC Rule Source: https://docs.fincode.technology/api/ciam/edit-kyc-rule PUT /admin/compliance/edit-kyc-rule Updates an existing KYC rule. # Edit Customer Profile Source: https://docs.fincode.technology/api/ciam/edit-profile PUT /usermanagement/profile-edit Updates the profile details of the currently authenticated customer. Updates the profile of the customer who owns the supplied `X-Auth-Token`. Only `REGISTERED_CUSTOMER` tokens are accepted — staff tokens cannot call this endpoint. ## Request Headers JWT Access Token of the authenticated customer. Platform identifier. Use `fincode`. Unique request identifier. ## Request Body Customer's first name. Customer's last name. Customer's phone number. International dialing code for the phone number (e.g. `+44`). Customer's email address. Date of birth in ISO format (e.g. `1990-05-15T00:00:00+01:00`). ISO 3166-1 alpha-3 nationality code (e.g. `NGA`, `GBR`). Gender. Accepted values: `MALE`, `FEMALE`, `OTHER`. Customer type. Accepted values: `INDIVIDUAL`, `COMPANY`. Company name — applicable when `customerType` is `COMPANY`. Customer's occupation. Customer's address. Street address line 1 Street address line 2 ISO 3166-1 alpha-3 country code (e.g. `GBR`) Postcode / ZIP code City New password (if the customer wants to change it). Must match `password` when changing password. Additional dynamic fields specific to your configuration. ## Response Returns a `ProfileDetailsResponseDTO` with the updated customer profile. `SUCCESS` or `FAILED`. Updated profile details. The customer's userId (UUID). The customer's short code. First name. Last name. Email address. Phone number. ## Code Example ```bash cURL theme={null} curl -X PUT 'https://{your-domain}.fincode.software/api/v6/services/usermanagement/profile-edit' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'Content-Type: application/json' \ --header 'platform: fincode' \ --header 'uuid: 200' \ --data '{ "firstName": "Jane", "lastName": "Doe", "phone": "+447912345678", "dialingCode": "+44", "nationality": "NGA", "address": { "address1": "10 Sample Street", "city": "London", "postcode": "EC1A 1BB", "countryIso3": "GBR" } }' ``` # External Screening Webhook Source: https://docs.fincode.technology/api/ciam/external-screening-webhook POST /compliance/external-screening/webhooks/{provider-code} Receives verification results from an external KYC provider and closes the outstanding compliance rule. Configure this URL as the webhook callback endpoint in your KYC provider account settings. This is a one-time setup, not per customer. When the customer completes verification, your provider calls this endpoint. the platform reads the reference you embedded in the verification session and uses it to locate the correct customer record and close the outstanding KYC rule. ## Behaviour | Provider Decision | Outcome | | - | - | | `APPROVED` | KYC rule is marked as submitted and the compliance record is updated | | `DECLINED` | KYC rule is reset so the customer can retry verification | | `PENDING` / `REVIEW` | Event is acknowledged but no action is taken — only final decisions are processed | ## Requirements The webhook payload must echo back the reference UUID returned by the [Initiate External KYC Provider](/api/ciam/initiate-external-provider) endpoint, in the external reference field your provider uses for correlation IDs. Without it, the result cannot be matched to a customer and will be rejected. # Fetch Organisation Preference Source: https://docs.fincode.technology/api/ciam/fetch-organisaction-preference GET /admin/organisation-preference-management/fetch-organisaction-preference Fetches organisation preferences. # Find Customer By Name or Phone Source: https://docs.fincode.technology/api/ciam/find-customer-by-name-or-phone-no GET /usermanagement/find-customer-by-name-or-phone-no/{search-criteria} Search for existing customers by name or phone number. Search for customers by partial name or phone number. Returns a list of matching customer records. Requires an authenticated `REGISTERED_CUSTOMER`, `MANAGER`, or `AGENTS` token. ## Request Headers The **JWT Access Token** of the authenticated user. Platform identifier. Use `fincode`. Unique request identifier. ## Path Parameters The search term — a partial or full customer name, or a phone number. Must not be blank. ## Response Returns a list of matching customers under `data.senders`. Each item has: | Field | Type | Description | | - | - | - | | `userId` | string | The customer's user ID (UUID). Use this as the identifier in all subsequent API calls. | | `customerCode` | string | The customer's short alphanumeric code. | | `firstName` | string | First name | | `lastName` | string | Last name | | `commonName` | string | Display name (company name for COMPANY type, full name otherwise) | | `phone` | string | Phone number | | `email` | string | Email address | | `dob` | string | Date of birth | | `country` | string | ISO country code of the customer's address | | `type` | string | Customer type — `INDIVIDUAL` or `COMPANY` | | `profilePhoto` | string | URL to the customer's profile image | ## Code Example ```bash cURL theme={null} curl -X GET 'https://{your-domain}.fincode.software/api/v6/services/usermanagement/find-customer-by-name-or-phone-no/Ada' \ --header 'X-Auth-Token: YOUR_TOKEN' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` # Initiate Compliance Action Source: https://docs.fincode.technology/api/ciam/initiate-compliance-action GET /compliance/initiate-awaiting-compliance-action/{customer-kyc-record-id} Triggers a specific pending KYC compliance action for a customer and returns the data needed to complete it. Call this endpoint once for each outstanding requirement returned by the [Awaiting Compliance Requirements](/api/ciam/awaiting-compliance-requirements) endpoint. Initiating an action causes the platform to begin processing it on our side. Depending on the action type, this may: * Send a verification email to the customer (email verification) * Send an OTP to the customer's phone (phone number verification) * Return verification session details (eKYC) The `customer-kyc-record-id` in the path is the ID of the specific compliance record returned in the awaiting requirements list. Call this endpoint once per action, not once for all actions. **Using an external provider that handles email and phone verification?** If your KYC provider performs contact verification as part of its flow, you must first enable `doNotForwardEmailVerification` and/or `doNotForwardPhoneVerification` in your agent (PayCenter) settings. Without this, customers will receive duplicate verification messages — one from your provider and one from the platform. Once configured, use [Verify Contact](/api/ciam/verify-contact) to notify the platform when your provider has confirmed a customer's email or phone. # Initiate External KYC Provider Source: https://docs.fincode.technology/api/ciam/initiate-external-provider POST /compliance/external-provider/initiate Registers an external KYC provider session with the platform and returns a reference to embed in the provider session. Use this endpoint when your client uses their own KYC provider instead of the platform's built-in provider. Calling this endpoint creates a compliance tracking record on our side and returns a unique `reference`. Your client must pass this reference to their KYC provider as the external user identifier (e.g. `externalUserId`, `correlationId`, or equivalent) when starting the verification session. When the customer completes verification, the provider sends a webhook to the platform. We use the `reference` echoed back in that webhook to match the result to the correct customer record and close the outstanding KYC rule. ## Request Body | Field | Type | Required | Description | | - | - | - | - | | `userId` | string | Yes | The customer's user ID returned from the register-customer endpoint | | `customerEmail` | string | Yes | The customer's email address | | `ruleId` | string | Yes | The eKYC rule ID from the awaiting compliance requirements list | | `correlationId` | string | No | Your own reference for this customer (e.g. your internal profile ID). If provided, the platform stores it and uses it to match incoming webhooks when your provider echoes it back as the external user identifier. If omitted, the platform generates a UUID reference instead. | ## Response The response `data` object contains a `reference` string. If you passed a `correlationId`, the reference echoes it back. If you did not, it is a platform-generated UUID. Either way, pass this value to your KYC provider as the external user identifier so the platform can match the webhook result to the correct customer. **Option B clients (own KYC provider):** Pass your internal profile ID or user ID as `correlationId`. Your KYC provider must send it back as the external user identifier in the webhook payload. The platform uses this to link the verification result to the customer record. # KYC Detail By ID Source: https://docs.fincode.technology/api/ciam/kyc-detail-by-id GET /admin/compliance/kyc-detail/{id} Retrieves KYC details by ID. # KYC Requirements by Country Source: https://docs.fincode.technology/api/ciam/kyc-requirements-by-isocountry GET /complaince/kyc-requirements-by-isocountry/{countryIso}/{triggerPoint} # List AML Rules Source: https://docs.fincode.technology/api/ciam/list-aml-rules GET /admin/compliance/list-aml-rules Lists AML rules. # List Connectors Source: https://docs.fincode.technology/api/ciam/list-connectors GET /admin/connector-management/list-connectors Lists connectors. # List Customers Source: https://docs.fincode.technology/api/ciam/list-customers GET /admin/customer-management/list-customers Returns a paginated list of customers for the authenticated manager. Returns a paginated, filterable list of customers in the pay centre. Requires a `MANAGER` token. ## Request Headers JWT Access Token of an authenticated manager. Platform identifier. Use `fincode`. Unique request identifier. ## Query Parameters Page number (1-based). Defaults to `1`. Number of records per page. Defaults to `20`. Free-text search by customer name, email, or phone number. Filter by verification status. Common values: `VERIFIED`, `UNVERIFIED`, `PENDING`. Filter by a specific pay centre ID. Defaults to the pay centre of the authenticated manager. Filter by customer profile type. ## Code Example ```bash cURL theme={null} curl -X GET 'https://{your-domain}.fincode.software/api/v6/services/admin/customer-management/list-customers?page=1&size=20&search=Jane' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` # List Employees Source: https://docs.fincode.technology/api/ciam/list-employees GET /admin/employee-management/list-employees Lists employees. # Organisation Compliance Policy Source: https://docs.fincode.technology/api/ciam/list-organisation-compliance-policy GET /compliance/list-organisation-compliance-policy Retrieves the KYC rules and transaction rules configured for the organisation. Call this endpoint to retrieve the full set of compliance rules your organisation has configured — both KYC identity rules and business transaction rules. Use it to understand what checks are in place before calling the per-customer [Pre-Transaction Compliance Checklist](/api/ciam/compliance-checklist). All authenticated user types can call this endpoint. ## Request Headers JWT Access Token of the authenticated user. Platform identifier. Use `fincode`. Unique request identifier. ## Response `SUCCESS` or `FAILED`. The KYC identity rules configured for this organisation. Each item describes a rule that may be applied to a customer based on their risk profile. The business transaction rules configured for this organisation. These rules may trigger AML document requirements at the point of booking a transfer. ## Code Example ```bash cURL theme={null} curl -X GET 'https://{your-domain}.fincode.software/api/v6/services/compliance/list-organisation-compliance-policy' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` ```javascript Node.js theme={null} const axios = require('axios'); async function getCompliancePolicy(accessToken) { const response = await axios.get( 'https://{your-domain}.fincode.software/api/v6/services/compliance/list-organisation-compliance-policy', { headers: { 'X-Auth-Token': accessToken, 'platform': 'fincode', 'uuid': '200', }, } ); return response.data.data; } ``` # List Pay Centers by Type Source: https://docs.fincode.technology/api/ciam/list-paycenters-by-type GET /branches/list-paycenters-by-type/{type} Lists pay centers for a specific type. # List Allocated Payout Points Source: https://docs.fincode.technology/api/ciam/listallocatedpayoutpoints POST /branches/listallocatedpayoutpoints Lists allocated payout points. # List Payment Collectors by Address Source: https://docs.fincode.technology/api/ciam/listpaymentcollectorsbyaddress POST /branches/listpaymentcollectorsbyaddress Lists payment collectors for an address. # List Payout Points Source: https://docs.fincode.technology/api/ciam/listpayoutpoints POST /branches/listpayoutpoints Lists payout points. # List Pay Points Source: https://docs.fincode.technology/api/ciam/listpaypoints POST /branches/listpaypoints Lists pay points. # OTP Verification Source: https://docs.fincode.technology/api/ciam/otp-verification GET /securitymanagement/otp-verification/{email}/{verification-code} Verifies a one-time code and marks the matching VERIFY_ACCOUNT_VIA_EMAIL or VERIFY_ACCOUNT_VIA_PHONE_NUMBER KYC rule as complete. This endpoint verifies a one-time code against a pending `VERIFY_ACCOUNT_VIA_EMAIL` or `VERIFY_ACCOUNT_VIA_PHONE_NUMBER` compliance requirement and marks the matching record as complete. **Email verification** — called automatically when the customer clicks the verification link sent to their email address. The link takes the form: ``` {domain}/auth/verification-success?email={email}&c={verification-code} ``` The frontend extracts the `email` and `c` values from the link and passes them as path parameters. No manual input is required from the customer. **Phone verification** — called when the customer submits the 6-digit code sent to their phone number via SMS. The frontend passes the customer's registered email address and the code they entered. ## Request ``` GET /securitymanagement/otp-verification/{email}/{verification-code} ``` No request body or authentication token is required. ## Path Parameters | Parameter | Type | Required | Description | | - | - | - | - | | `email` | String | Yes | The customer's registered email address | | `verification-code` | String | Yes | The one-time code from the email link or the 6-digit SMS code entered by the customer | ## Example Requests **Email verification** (from link click): ``` GET /securitymanagement/otp-verification/john.doe@example.com/a1b2c3d4e5 ``` **Phone verification** (from SMS code entry): ``` GET /securitymanagement/otp-verification/john.doe@example.com/482910 ``` ## Response ```json theme={null} { "status": "SUCCESS", "data": { "smsVerified": true } } ``` | Field | Type | Description | | - | - | - | | `status` | String | `SUCCESS` or `FAILED` | | `data.smsVerified` | Boolean | `true` if the code matched and the KYC rule was marked complete | ## Notes * No authentication token is required. * The same endpoint handles both email and phone verification — the backend resolves which KYC rule to mark complete based on the pending record matching the provided email and code. # Get Pay Centre By ID Source: https://docs.fincode.technology/api/ciam/pay-centre-by-id GET /admin/pay-centre-management/pay-centre-by/{id} Retrieves pay centre details by ID. # Payout Center Branches Source: https://docs.fincode.technology/api/ciam/payoutCenter-branches POST /branches/payoutCenter Lists payout center branches. # Product Payment Details Source: https://docs.fincode.technology/api/ciam/product-payment-details POST /admin/account-product/payment-details Retrieves product payment details. # Customer Profile Source: https://docs.fincode.technology/api/ciam/profile GET /usermanagement/profile Retrieves the detailed profile information for the authenticated user. Retrieves comprehensive profile information for the authenticated user, based on the **JWT Access Token** provided in the headers. ## Request Headers This endpoint requires a valid **Access Token** for authorization. The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint.       Platform identifier. Use `fincode`.       Unique request identifier. ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v6/services/usermanagement/profile' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` ```javascript Node.js theme={null} const axios = require("axios"); const BASE_URL = "https://{your-domain}.fincode.software/api/v6/services/usermanagement"; async function getUserProfile(accessToken) { try { const response = await axios.get(`${BASE_URL}/profile`, { headers: { "X-Auth-Token": accessToken, platform: "fincode", uuid: "200", }, }); console.log("Profile fetched successfully!"); console.log("User:", response.data.firstName, response.data.lastName); console.log("Role:", response.data.role); return response.data; } catch (error) { console.error( "Failed to fetch profile:", error.response?.data || error.message ); throw error; } } // Usage Example const accessToken = "YOUR_JWT_ACCESS_TOKEN"; getUserProfile(accessToken); ``` # Reset Password Source: https://docs.fincode.technology/api/ciam/reset-password GET /securitymanagement/reset-password/{email} Sends a password reset email to the customer. No authentication required. Triggers a password reset email to the specified email address. No `X-Auth-Token` is required — this is a public endpoint called before login. The email must belong to a registered customer on the pay centre domain. ## Path Parameters The email address of the customer who wants to reset their password. ## Request Headers Platform identifier. Use `fincode`. Unique request identifier. ## Response `SUCCESS` if the reset email was sent, `FAILED` otherwise. A description of the result. ## Code Example ```bash cURL theme={null} curl -X GET 'https://{your-domain}.fincode.software/api/v6/services/securitymanagement/reset-password/customer@example.com' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` # Submit CRA Form Source: https://docs.fincode.technology/api/ciam/submit-cra POST /admin/compliance/submit-cra Submits the data collected from a dynamic form, such as a Customer Risk Assessment (CRA), for processing and compliance evaluation. This endpoint is used to submit the collected data from dynamic forms (e.g., CRA or KYC forms). The system validates the input, updates the customer's compliance status, and may automatically trigger the next step in the enrolment process (like external screening). # Update AML Rules Source: https://docs.fincode.technology/api/ciam/update-aml-rules PUT /admin/compliance/update-aml-rules Updates AML rules. # Update Connector Instance Source: https://docs.fincode.technology/api/ciam/update-connector-instance PUT /admin/connector-management/update-connector-instance Updates a connector instance. # Update Organisation Preference Source: https://docs.fincode.technology/api/ciam/update-organisaction-preference PUT /admin/organisation-preference-management/update-organisaction-preference Updates organisation preferences. # Upload Profile Picture Source: https://docs.fincode.technology/api/ciam/upload-profile-picture PUT /documentmanagement/upload-profile-picture Uploads a profile picture. # Verify Contact Source: https://docs.fincode.technology/api/ciam/verify-contact POST /compliance/external-provider/verify-contact Notifies the platform that a customer email or phone has been verified externally, triggering the full KYC lifecycle. Use this endpoint when your agent handles email or phone verification independently, instead of having the platform send the verification link or OTP to the customer. Calling this endpoint marks the outstanding email or phone KYC requirement as fulfilled and triggers the full KYC lifecycle automatically — including risk score adjustment, compliance decision re-evaluation, and account approval if all requirements are met. ## When to Use This Endpoint This endpoint is relevant when your agent has one or both of the following settings enabled on the agent configuration: | Setting | Behaviour when enabled | | - | - | | `doNotForwardEmailVerification` | the platform does **not** send the email verification link. Your system must verify the customer's email and call this endpoint with `type=EMAIL`. | | `doNotForwardPhoneVerification` | the platform does **not** send the phone OTP. Your system must verify the customer's phone and call this endpoint with `type=PHONE_NUMBER`. | If neither setting is enabled, the platform sends the verification automatically when you call [Initiate Compliance Action](/api/ciam/initiate-compliance-action) and this endpoint is not needed. ## Request Parameters | Parameter | Type | Required | Description | | - | - | - | - | | `userId` | string | Yes | The customer's user ID returned from the register-customer endpoint | | `type` | enum | Yes | The contact type to verify. One of: `EMAIL`, `PHONE_NUMBER` | ## Response The response `data` object contains the verification result: | Field | Type | Description | | - | - | - | | `type` | enum | The contact type that was verified. One of: `EMAIL`, `PHONE_NUMBER` | | `verified` | boolean | Whether the requirement was marked as fulfilled | | `rawProviderResponse` | string | The raw response from the verification provider | ## Behaviour When this endpoint is called: 1. the platform locates the outstanding KYC requirement for the specified `userId` and contact `type`. 2. The requirement is marked as fulfilled. 3. The customer's risk score is updated to reflect the completed requirement. 4. The compliance decision is re-evaluated against the configured thresholds. 5. If the customer meets the approval threshold, their account is confirmed automatically. If no outstanding requirement is found for the given `userId` and `type`, the call succeeds but no KYC action is taken. # Verify Customer Source: https://docs.fincode.technology/api/ciam/verify-customer GET /admin/customer-management/verify-customer/{id} Manually verifies and activates a customer account. Requires MANAGER or ADMIN token. Marks a customer account as verified. The `{id}` path parameter is the customer's userId (UUID). Only `ADMIN` and `MANAGER` tokens are accepted. ## Path Parameters The customer's `userId` (UUID) — the `userIdKey` value from the register-customer or list-customers response. ## Request Headers JWT Access Token of an authenticated manager or admin. Platform identifier. Use `fincode`. Unique request identifier. ## Code Example ```bash cURL theme={null} curl -X GET 'https://{your-domain}.fincode.software/api/v6/services/admin/customer-management/verify-customer/{userId}' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` # Verify Login OTP Source: https://docs.fincode.technology/api/ciam/verify-login-otp POST /securitymanagement/verify-login-otp Verifies the one-time password sent as part of two-factor authentication at login. Verifies the OTP sent to the customer during login (two-factor authentication). Call this after a successful `/login` response that requires OTP confirmation. Requires the temporary `X-Auth-Token` returned by the login step. ## Request Headers The JWT token returned from the login step. Platform identifier. Use `fincode`. Unique request identifier. ## Request Body The one-time password received by the customer via email or SMS. ## Response `SUCCESS` if the OTP is valid, `FAILED` otherwise. `otp verified` on success. ## Code Example ```bash cURL theme={null} curl -X POST 'https://{your-domain}.fincode.software/api/v6/services/securitymanagement/verify-login-otp' \ --header 'X-Auth-Token: YOUR_TEMP_JWT_TOKEN' \ --header 'Content-Type: application/json' \ --header 'platform: fincode' \ --header 'uuid: 200' \ --data '{"otp": "123456"}' ``` # View Password Policy Source: https://docs.fincode.technology/api/ciam/view-password-policy GET /admin/security/view-password-policy Views the password policy. # Awaiting Payment Actions Source: https://docs.fincode.technology/api/deposit-engine/awaiting-payment-actions POST /paymentmanagement/awaiting-payment-actions Perform actions on an awaiting payment record such as marking it as 'paid' or 'cancel'. Returns the updated list of awaiting payments based on filters. This endpoint allows a user (excluding cashiers) to **perform actions** on an existing awaiting bank transfer payment. Supported actions include: * Marking a payment as **paid** * Marking a payment as **cancelled** * Returning an **updated list of awaiting payments** using optional date and currency filters ## Authentication Authentication token obtained after login. Device UUID used for request tracking. Platform identifier (e.g., "WEB", "ANDROID", "IOS"). *** ## Request Body Unique ID of the awaiting payment to update. Action to perform. Accepted values: * `"paid"` * `"cancel"` Currency used to filter updated list results (e.g., `"USD"`, `"NGN"`). Start date (`dd/MM/yyyy`) for fetching updated awaiting payments. End date (`dd/MM/yyyy`) for fetching updated awaiting payments. ## Code Examples ```bash cURL theme={null} curl --request POST \ --url "https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/awaiting-payment-actions" \ --header 'Content-Type: application/json' \ --header 'X-Auth-Token: your_auth_token' \ --header 'uuid: your_device_uuid' \ --header 'platform: WEB' \ --data '{ "awaitingPaymentId": "AP12345", "subAction": "paid", "selectedCurrency": "USD", "fromDate": "01/01/2024", "toDate": "31/01/2024" }' ``` ```javascript JavaScript theme={null} const response = await fetch( "https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/awaiting-payment-actions", { method: "POST", headers: { "Content-Type": "application/json", "X-Auth-Token": authToken, "uuid": deviceUuid, "platform": "WEB" }, body: JSON.stringify({ awaitingPaymentId: "AP12345", subAction: "paid", selectedCurrency: "USD", fromDate: "01/01/2024", toDate: "31/01/2024" }) } ); const data = await response.json(); ``` ```python Python theme={null} import requests url = "https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/awaiting-payment-actions" headers = { "Content-Type": "application/json", "X-Auth-Token": "your_auth_token", "uuid": "your_device_uuid", "platform": "WEB" } payload = { "awaitingPaymentId": "AP12345", "subAction": "paid", "selectedCurrency": "USD", "fromDate": "01/01/2024", "toDate": "31/01/2024" } response = requests.post(url, json=payload, headers=headers) data = response.json() ``` # List Awaiting Payments Source: https://docs.fincode.technology/api/deposit-engine/awaiting-payments GET /paymentmanagement/awaiting-payments Retrieve all pending/awaiting payment records for a customer based on filters such as date range, currency, and reference search. ## Overview This endpoint retrieves **all awaiting payments** for the authenticated customer or organization within a specified date range and currency. It is typically used by dashboards, finance teams, or customer apps to list: * Pending bank transfers * Confirmations awaiting customer or MTO verification * Payments requiring follow-up actions * Items awaiting funding or payout Use this endpoint to display or filter all awaiting/pending payments for your customers. ## Authentication Authentication token obtained after login. Device UUID used for request tracking. Platform identifier (e.g., "WEB", "ANDROID", "IOS"). ## Query Parameters Pagination page number (default: `1`) Number of records per page (default: `20`) ## Request Body Currency code used for filtering (e.g., `"USD"`, `"NGN"`, `"GBP"`). Start date in format `dd/MM/yyyy` (e.g., `"01/01/2024"`). End date in format `dd/MM/yyyy` (e.g., `"31/01/2024"`). Optional payment reference or identifier used for fuzzy search. ## Request Example ```bash cURL theme={null} curl --request GET \ --url "https://api.example.com/awaiting-payments?page=1&size=20" \ --header 'Content-Type: application/json' \ --header 'X-Auth-Token: your_auth_token' \ --header 'uuid: your_device_uuid' \ --header 'platform: WEB' \ --data '{ "selectedCurrency": "USD", "fromDate": "01/01/2024", "toDate": "31/01/2024", "searchablePaymentReference": "TRX" }' ``` ```javascript JavaScript theme={null} const response = await fetch( 'https://api.example.com/awaiting-payments?page=1&size=20', { method: 'GET', headers: { 'Content-Type': 'application/json', 'X-Auth-Token': authToken, 'uuid': deviceUuid, 'platform': 'WEB' }, body: JSON.stringify({ selectedCurrency: 'USD', fromDate: '01/01/2024', toDate: '31/01/2024', searchablePaymentReference: 'TRX' }) } ); const data = await response.json(); ``` ```python Python theme={null} import requests url = "https://api.example.com/awaiting-payments?page=1&size=20" headers = { "Content-Type": "application/json", "X-Auth-Token": "your_auth_token", "uuid": "your_device_uuid", "platform": "WEB" } payload = { "selectedCurrency": "USD", "fromDate": "01/01/2024", "toDate": "31/01/2024", "searchablePaymentReference": "TRX" } response = requests.get(url, json=payload, headers=headers) data = response.json() ``` ## Response Example ```json 200 OK theme={null} { "status": "SUCCESS", "responseCode": 200, "data": { "awaitingPayments": [ { "id": "AP12345", "payableType": "TRANSACTION", "bankTransferFollowupActionType": "AUTO_CONFIRM_TRANSACTION", "bankTransferLifeCycle": "AWAITING_BANK_TRANSFER_PAYMENT", "mtoPaymentConfirmtionType": "NOT_CONFIRMED", "customerConfirmedPaymentDate": null, "creationDate": "2024-01-10T12:30:00", "currency": "USD", "requestedBankTransferAmount": 150, "searchablePaymentReference": "TRX-90832", "payerBankTransferReference": "BTREF123" } ] } } ``` ```json 401 Unauthorized theme={null} { "status": "FAILED", "message": "Invalid device info.", "responseCode": 401 } ``` ```json 500 Error theme={null} { "status": "FAILED", "message": "Please send currency !", "responseCode": 500 } ``` ## Use Cases ### 1. Display Awaiting Payments in a Dashboard ```javascript theme={null} const res = await getAwaitingPayments(filters); res.data.awaitingPayments.forEach(entry => { console.log(entry.searchablePaymentReference, entry.requestedBankTransferAmount); }); ``` ### 2. Filter Payments by Date Range ```javascript theme={null} await getAwaitingPayments({ selectedCurrency: "GBP", fromDate: "01/02/2024", toDate: "10/02/2024" }); ``` ### 3. Identify Items Requiring Follow-Up ```javascript theme={null} const items = res.data.awaitingPayments.filter( p => p.bankTransferFollowupActionType === 'MARK_AS_PENDING_TRANSACTION' ); ``` ## Error Handling ```javascript theme={null} try { const res = await fetch('/awaiting-payments?page=1&size=20', { ...config }); const data = await res.json(); if (data.status === 'FAILED') { console.error("Error:", data.message); } } catch (err) { console.error("Network/server error:", err); } ``` ## Important Notes * Authentication is mandatory * `selectedCurrency`, `fromDate`, and `toDate` are required * Users with role `CASHIER` are not allowed * Date format must be `dd/MM/yyyy` * The lifecycle status helps identify pending, received, or completed items * Reference search improves lookup of specific payments ## Next Steps Take follow-up actions (mark pending, confirm, etc.) Mark a payment as 'I will pay later' Retrieve applicable charges for payments View available payment methods ``` ``` # Bank Pay Later (Wallet) Source: https://docs.fincode.technology/api/deposit-engine/bank-iwillpaylater PUT /paymentmanagement/bank-iwillpaylater-wallet/{pcn}/{payableType_String} Notify the system that a customer will pay later via bank transfer. Creates an awaiting payment entry for the given PCN and payable type. This endpoint allows a user to **mark a payment as 'I will pay later'**. It is typically used when a customer cannot pay immediately but wants the payment recorded in the **Awaiting Payments List** for follow-up. This API is used by dashboards, finance teams, or back-office operations to: * Record a payment intent without actual funds transfer * Generate an awaiting payment entry tied to the PCN and payable type * Allow subsequent operations to track or confirm the payment ## Authentication Authentication token obtained after login. Device UUID used for request tracking. Platform identifier (e.g., "WEB", "ANDROID", "IOS"). ## Path Parameters Payment code number (PCN) of the payable item. Minimum length: 3. Payable type associated with the PCN. Minimum length: 5. Supported values correspond to the `PayableType` enum. ## Code Examples ```bash cURL theme={null} curl --request PUT \ --url "https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/bank-iwillpaylater-wallet/PCN123/TRANSACTION" \ --header 'Content-Type: application/json' \ --header 'X-Auth-Token: your_auth_token' \ --header 'uuid: your_device_uuid' \ --header 'platform: WEB' ``` ```javascript JavaScript theme={null} const response = await fetch( "https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/bank-iwillpaylater-wallet/PCN123/TRANSACTION", { method: "PUT", headers: { "Content-Type": "application/json", "X-Auth-Token": authToken, "uuid": deviceUuid, "platform": "WEB" } } ); const data = await response.json(); ``` ```python Python theme={null} import requests url = "https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/bank-iwillpaylater-wallet/PCN123/TRANSACTION" headers = { "Content-Type": "application/json", "X-Auth-Token": "your_auth_token", "uuid": "your_device_uuid", "platform": "WEB" } response = requests.put(url, headers=headers) data = response.json() ``` ## Use Cases ### 1. Mark a Payment as "I Will Pay Later" ```javascript theme={null} await bankIWillPayLater("PCN123", "TRANSACTION"); ``` ### 2. Track Payments Awaiting Customer Action ```javascript theme={null} const response = await bankIWillPayLater("PCN678", "BILL"); console.log(response.data.ref, response.data.payableItemId); ``` # Make Payment from Wallet Source: https://docs.fincode.technology/api/deposit-engine/make-payment-from-wallet POST /paymentmanagement/makepaymentfromwalletaccount Process payment for any payable item using customer wallet balance. This endpoint allows customers to pay for transactions, bill payments, wallet funding, or any other payable item using their wallet balance. The system automatically debits the customer's wallet and updates the payment status. ## Authentication Authentication token obtained from login Device UUID for request tracking Platform identifier (e.g., "WEB", "MOBILE", "IOS", "ANDROID") ## Request Body Type of payable item to process **Options:** * `TRANSACTION` - Remittance/money transfer * `WALLET` - Generic wallet payment * `WALLET_CUSTOMER` - Personal wallet payment * `BILL` - Bill payment * `MERCHANT` - Product payment * `WITHDRAWAL` - Wallet withdrawal Unique identifier of the payable item Customer's account password for authentication Wallet account ID to debit from Total amount to be debited including fees and taxes Reference number for the payment (can be auto-generated) Specific wallet account number (if customer has multiple accounts) Currency code of the wallet account **Examples:** `USD`, `GBP`, `NGN`, `EUR` One-Time Password for Strong Customer Authentication (if enabled) Transaction PIN for additional security (if enabled) ## Code Examples ```bash cURL theme={null} curl --request POST \ --url https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/makepaymentfromwalletaccount \ --header 'Content-Type: application/json' \ --header 'X-Auth-Token: your_auth_token' \ --header 'uuid: device_uuid' \ --header 'platform: WEB' \ --data '{ "payableType": "TRANSACTION", "payAbleId": "txn_abc123", "password": "user_password", "accountId": "wallet_456", "totalCheckOutAmount": 105.50, "paymentGatewayRef": "ref_789", "accountNumber": "1234567890", "paymentAccountNumbeCurrencyCode": "USD", "pin": "1234" }' ``` ```javascript JavaScript theme={null} const payFromWallet = async (paymentData) => { const response = await fetch('https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/makepaymentfromwalletaccount', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Auth-Token': 'your_auth_token', 'uuid': 'device_uuid', 'platform': 'WEB' }, body: JSON.stringify({ payableType: 'TRANSACTION', payAbleId: 'txn_abc123', password: 'user_password', accountId: 'wallet_456', totalCheckOutAmount: 105.50, paymentGatewayRef: 'ref_789', accountNumber: '1234567890', paymentAccountNumbeCurrencyCode: 'USD', pin: '1234' }) }); return await response.json(); }; ``` ```python Python theme={null} import requests url = "https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/makepaymentfromwalletaccount" headers = { "Content-Type": "application/json", "X-Auth-Token": "your_auth_token", "uuid": "device_uuid", "platform": "WEB" } payload = { "payableType": "TRANSACTION", "payAbleId": "txn_abc123", "password": "user_password", "accountId": "wallet_456", "totalCheckOutAmount": 105.50, "paymentGatewayRef": "ref_789", "accountNumber": "1234567890", "paymentAccountNumbeCurrencyCode": "USD", "pin": "1234" } response = requests.post(url, json=payload, headers=headers) data = response.json() ``` ## Use Cases ### 1. Pay for Money Transfer ```javascript theme={null} const payForRemittance = async (transactionId) => { // First, get payment methods to confirm wallet balance const methods = await getPaymentMethods(transactionPCN); const walletMethod = methods.data.paymentMethodsMetadata .find(m => m.paymentMethod === 'E_WALLET'); if (!walletMethod.metadata.sufficient) { throw new Error('Insufficient wallet balance'); } // Process payment from wallet const payment = await fetch('/makepaymentfromwalletaccount', { method: 'POST', headers: headers, body: JSON.stringify({ payableType: 'TRANSACTION', payAbleId: transactionId, password: userPassword, accountId: walletAccountId, totalCheckOutAmount: walletMethod.totalAmount, paymentGatewayRef: generateRef(), paymentAccountNumbeCurrencyCode: 'USD' }) }); return await payment.json(); }; ``` ### 2. Pay Bill from Wallet ```javascript theme={null} const payBill = async (billId, amount) => { const response = await fetch('/makepaymentfromwalletaccount', { method: 'POST', headers: headers, body: JSON.stringify({ payableType: 'BILL', payAbleId: billId, password: userPassword, accountId: walletAccountId, totalCheckOutAmount: amount, paymentGatewayRef: `BILL_${Date.now()}`, paymentAccountNumbeCurrencyCode: 'NGN', pin: transactionPIN }) }); const result = await response.json(); if (result.status === 'SUCCESS') { console.log('Bill paid successfully'); } return result; }; ``` ### 3. Fund Another Wallet ```javascript theme={null} const fundWallet = async (fundingRequestId) => { const response = await fetch('/makepaymentfromwalletaccount', { method: 'POST', headers: headers, body: JSON.stringify({ payableType: 'WALLET_CUSTOMER', payAbleId: fundingRequestId, password: userPassword, accountId: sourceWalletId, totalCheckOutAmount: fundingAmount, paymentGatewayRef: `FUND_${Date.now()}`, accountNumber: sourceAccountNumber, paymentAccountNumbeCurrencyCode: 'USD' }) }); return await response.json(); }; ``` # Notify Bank Transfer Payment Source: https://docs.fincode.technology/api/deposit-engine/notify-bank-transfer-payment POST /paymentmanagement/notify-bank-transfer-payment Notify the system that a customer has made a bank transfer payment, alerting Admin to verify or take appropriate action. This endpoint allows a customer to **notify the system** about a bank transfer payment. Supported options include: * `bank_pay_later` — Customer will pay later; adds item to awaiting payments list * `bank_paid_now` — Customer confirms payment has been made * `mistake` — Customer reports a payment was made by mistake ## Authentication Authentication token obtained after login. Device UUID used for request tracking. Platform identifier (e.g., "WEB", "ANDROID", "IOS"). *** ## Request Body Payment code number associated with the transaction or transfer. Action the customer is notifying. Options: * `bank_pay_later` * `bank_paid_now` * `mistake` Type of payable item. Defaults to `TRANSACTION` if not specified. ## Code Examples ```bash cURL theme={null} curl --request POST \ --url "https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/notify-bank-transfer-payment" \ --header 'Content-Type: application/json' \ --header 'X-Auth-Token: your_auth_token' \ --header 'uuid: your_device_uuid' \ --header 'platform: WEB' \ --data '{ "pcn": "PCN12345", "option": "bank_paid_now", "payAbleType": "TRANSACTION" }' ``` ```javascript JavaScript theme={null} const response = await fetch( "https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/notify-bank-transfer-payment", { method: "POST", headers: { "Content-Type": "application/json", "X-Auth-Token": authToken, "uuid": deviceUuid, "platform": "WEB" }, body: JSON.stringify({ pcn: "PCN12345", option: "bank_paid_now", payAbleType: "TRANSACTION" }) } ); const data = await response.json(); ``` ```python Python theme={null} import requests url = "https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/notify-bank-transfer-payment" headers = { "Content-Type": "application/json", "X-Auth-Token": "your_auth_token", "uuid": "your_device_uuid", "platform": "WEB" } payload = { "pcn": "PCN12345", "option": "bank_paid_now", "payAbleType": "TRANSACTION" } response = requests.post(url, json=payload, headers=headers) data = response.json() ``` ## Use Cases ### 1. Notify That Payment Has Been Made Now ```javascript theme={null} await notifyBankTransferPayment({ pcn: "PCN12345", option: "bank_paid_now" }); ``` *** ### 2. Notify That Payment Will Be Paid Later ```javascript theme={null} await notifyBankTransferPayment({ pcn: "PCN12345", option: "bank_pay_later" }); ``` *** ### 3. Notify a Payment Was Made by Mistake ```javascript theme={null} await notifyBankTransferPayment({ pcn: "PCN12345", option: "mistake" }); ``` # Payment Methods Charges Source: https://docs.fincode.technology/api/deposit-engine/payment-methods-charges POST /paymentmanagement/payment-methods-charges Retrieve applicable charges for a selected payment method based on transaction or transfer details. This endpoint allows a user to **calculate payment charges** associated with different payment methods. It supports scenarios including: * Customer transactions (`subAction = "transaction"`) * Money transfers (`subAction = "transfer"`) Charges are determined based on: * Selected payment method * Amount and currency * Organisation and customer country ## Authentication Authentication token obtained after login. Device UUID used for request tracking. Platform identifier (e.g., "WEB", "ANDROID", "IOS"). ## Request Body Payment code number. Required if `subAction = "transaction"`. Action type. Accepted values: * `"transaction"` * `"transfer"` Selected payment method. Must match `PaymentMethod` enum, e.g., `"ONLINE_CARD_PAYMENT"`, `"BANK_TRANSFER"`. Currency code for the transfer (required if `subAction = "transfer"`). Amount for the transfer (required if `subAction = "transfer"`). ## Code Examples ```bash cURL theme={null} curl --request POST \ --url "https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/payment-methods-charges" \ --header 'Content-Type: application/json' \ --header 'X-Auth-Token: your_auth_token' \ --header 'uuid: your_device_uuid' \ --header 'platform: WEB' \ --data '{ "subAction": "transfer", "payment_method": "BANK_TRANSFER", "currency": "USD", "amount": "150" }' ``` ```javascript JavaScript theme={null} const response = await fetch( "https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/payment-methods-charges", { method: "POST", headers: { "Content-Type": "application/json", "X-Auth-Token": authToken, "uuid": deviceUuid, "platform": "WEB" }, body: JSON.stringify({ subAction: "transfer", payment_method: "BANK_TRANSFER", currency: "USD", amount: "150" }) } ); const data = await response.json(); ``` ```python Python theme={null} import requests url = "https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/payment-methods-charges" headers = { "Content-Type": "application/json", "X-Auth-Token": "your_auth_token", "uuid": "your_device_uuid", "platform": "WEB" } payload = { "subAction": "transfer", "payment_method": "BANK_TRANSFER", "currency": "USD", "amount": "150" } response = requests.post(url, json=payload, headers=headers) data = response.json() ``` ## Use Cases ### 1. Retrieve Charges for a Transfer ```javascript theme={null} await paymentMethodsCharges({ subAction: "transfer", payment_method: "BANK_TRANSFER", currency: "USD", amount: "150" }); ``` ### 2. Retrieve Charges for a Transaction ```javascript theme={null} await paymentMethodsCharges({ subAction: "transaction", pcn: "PCN123", payment_method: "ONLINE_CARD_PAYMENT" }); ``` # Process Card Payment Source: https://docs.fincode.technology/api/deposit-engine/process-card-payment POST /paymentmanagement/process-card-payment Process a card payment by providing card details, transaction amount, and request type. Returns the payment gateway response. This endpoint allows a customer to **process a payment via card** by providing necessary card details. Supported payment flows include: * Authorizing a **card payment** * Returning detailed **transaction response** including status, issuer info, and merchant details ## Authentication Authentication token obtained after login. Device UUID used for request tracking. Platform identifier (e.g., "WEB", "ANDROID", "IOS"). ## Request Body 3-letter ISO currency code of the transaction (e.g., "USD", "NGN"). Primary Account Number (card number) of the customer. Card expiry date in `MM/yyyy` format. Card CVV/security code. Description of the request type (e.g., "purchase", "refund"). Amount to charge the card. Optional payment code number associated with the transaction. ## Code Examples ```bash cURL theme={null} curl --request POST \ --url "https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/process-card-payment" \ --header 'Content-Type: application/json' \ --header 'X-Auth-Token: your_auth_token' \ --header 'uuid: your_device_uuid' \ --header 'platform: WEB' \ --data '{ "currencyiso3a": "USD", "pan": "4111111111111111", "expirydate": "12/2025", "securitycode": "123", "requesttypedescriptions": "purchase", "baseamount": "150.00", "pcn": "PCN12345" }' ``` ```javascript JavaScript theme={null} const response = await fetch( "https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/process-card-payment", { method: "POST", headers: { "Content-Type": "application/json", "X-Auth-Token": authToken, "uuid": deviceUuid, "platform": "WEB" }, body: JSON.stringify({ currencyiso3a: "USD", pan: "4111111111111111", expirydate: "12/2025", securitycode: "123", requesttypedescriptions: "purchase", baseamount: "150.00", pcn: "PCN12345" }) } ); const data = await response.json(); ``` ```python Python theme={null} import requests url = "https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/process-card-payment" headers = { "Content-Type": "application/json", "X-Auth-Token": "your_auth_token", "uuid": "your_device_uuid", "platform": "WEB" } payload = { "currencyiso3a": "USD", "pan": "4111111111111111", "expirydate": "12/2025", "securitycode": "123", "requesttypedescriptions": "purchase", "baseamount": "150.00", "pcn": "PCN12345" } response = requests.post(url, json=payload, headers=headers) data = response.json() ``` # Fund Customer Wallet by Payment Token Source: https://docs.fincode.technology/api/deposit-engine/process-payment-with-token POST /paymentmanagement/processpaymentwithpaymenttoken Verify a payment token and process a payment request. If a token is provided, the payment gateway is used; otherwise, the wallet is used. This endpoint allows a customer to **fund their wallet account** either via a **payment token** or directly from the wallet. Supported payment flows include: * Using an **online card payment token** from a supported payment gateway * Funding via the **customer wallet** if no token is provided ## Authentication Authentication token obtained after login. Device UUID used for request tracking. Platform identifier (e.g., "WEB", "ANDROID", "IOS"). ## Request Body Type of payable item. Unique ID of the payable item to fund. Payment gateway token reference when using card payment. Payment gateway provider. Options: * `STRIPE_ACH` * `COINBASE_PAYMENT_API` * `POLI_PAYMENT_API` * `SECURE_TRADING` * `RAVE_FLUTTERWAVE` * `CUSTOM_POINT_OF_SALE` Method of payment. Options include: * `ONLINE_CARD_PAYMENT` * `E_WALLET` Total amount to process for checkout. Optional beneficiary phone number for payment processing. Optional password required for certain wallet payments. Optional account number for wallet or bank account payment. Currency code for the payment account, if applicable. ## Code Examples ```bash cURL theme={null} curl --request POST \ --url "https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/processpaymentwithpaymenttoken" \ --header 'Content-Type: application/json' \ --header 'X-Auth-Token: your_auth_token' \ --header 'uuid: your_device_uuid' \ --header 'platform: WEB' \ --data '{ "payableType": "TRANSACTION", "payAbleId": "PAY12345", "paymentGatewayRef": "TOKEN_98765", "supportedPaymentGateWayProvider": "RAVE_FLUTTERWAVE", "paymentMethod": "ONLINE_CARD_PAYMENT", "totalCheckOutAmount": 150.00, "accountNumber": "1234567890", "paymentAccountNumbeCurrencyCode": "USD" }' ``` ```javascript JavaScript theme={null} const response = await fetch( "https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/processpaymentwithpaymenttoken", { method: "POST", headers: { "Content-Type": "application/json", "X-Auth-Token": authToken, "uuid": deviceUuid, "platform": "WEB" }, body: JSON.stringify({ payableType: "TRANSACTION", payAbleId: "PAY12345", paymentGatewayRef: "TOKEN_98765", supportedPaymentGateWayProvider: "RAVE_FLUTTERWAVE", paymentMethod: "ONLINE_CARD_PAYMENT", totalCheckOutAmount: 150.00, accountNumber: "1234567890", paymentAccountNumbeCurrencyCode: "USD" }) } ); const data = await response.json(); ``` ```python Python theme={null} import requests url = "https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/processpaymentwithpaymenttoken" headers = { "Content-Type": "application/json", "X-Auth-Token": "your_auth_token", "uuid": "your_device_uuid", "platform": "WEB" } payload = { "payableType": "TRANSACTION", "payAbleId": "PAY12345", "paymentGatewayRef": "TOKEN_98765", "supportedPaymentGateWayProvider": "RAVE_FLUTTERWAVE", "paymentMethod": "ONLINE_CARD_PAYMENT", "totalCheckOutAmount": 150.00, "accountNumber": "1234567890", "paymentAccountNumbeCurrencyCode": "USD" } response = requests.post(url, json=payload, headers=headers) data = response.json() ``` # Supported Payment Methods Source: https://docs.fincode.technology/api/deposit-engine/supported-payment-methods POST /paymentmanagement/supported-payment-methods Retrieve available payment methods with charges, fees, and metadata for a specific transaction or payment amount. This endpoint returns all supported payment methods available for a transaction based on the customer's country, currency, amount, and payable type. It calculates fees, taxes, and exchange rates for each payment method. ## Authentication Authentication token obtained from login Device UUID for request tracking Platform identifier (e.g., "WEB", "MOBILE", "IOS", "ANDROID") ## Request Body Payment Control Number - unique identifier for the payable item Type of payable item **Options:** * `TRANSACTION` - Remittance/money transfer * `WALLET` - Generic wallet payment * `WALLET_CUSTOMER` - Personal wallet payment * `WALLET_PAYCENTER` - Agent wallet payment * `BILL` - Bill payment * `MERCHANT` - Product payment * `VOUCHER` - Voucher purchase * `WITHDRAWAL` - Wallet withdrawal Three-letter ISO country code (e.g., "USA", "GBR", "NGA") Three-letter currency code (e.g., "USD", "GBP", "NGN"). Required if PCN is not provided. Payment amount as string. Required if PCN is not provided. Application identifier for specific integrations Specific transaction type filter **Options:** * `ACCOUNTPAYMENT` - Bank transfer * `CASHPICKUP` - Cash pickup * `MOBILE_MONEY` - Mobile money * `WALLET` - Wallet payment * `BILL_PAYMENT` - Bill payment ## Code Examples ```bash cURL theme={null} curl --request POST \ --url https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/supported-payment-methods \ --header 'Content-Type: application/json' \ --header 'X-Auth-Token: your_auth_token' \ --header 'uuid: device_uuid' \ --header 'platform: WEB' \ --data '{ "pcn": "PCN123456789", "payAbleType": "TRANSACTION", "countryIsoCode3": "USA" }' ``` ```javascript JavaScript theme={null} const response = await fetch('https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/supported-payment-methods', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Auth-Token': 'your_auth_token', 'uuid': 'device_uuid', 'platform': 'WEB' }, body: JSON.stringify({ pcn: 'PCN123456789', payAbleType: 'TRANSACTION', countryIsoCode3: 'USA' }) }); const data = await response.json(); ``` ```python Python theme={null} import requests url = "https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/supported-payment-methods" headers = { "Content-Type": "application/json", "X-Auth-Token": "your_auth_token", "uuid": "device_uuid", "platform": "WEB" } payload = { "pcn": "PCN123456789", "payAbleType": "TRANSACTION", "countryIsoCode3": "USA" } response = requests.post(url, json=payload, headers=headers) data = response.json() ``` ## Use Cases ### 1. Display Payment Options Use this endpoint to show customers all available payment methods: ```javascript theme={null} // Fetch payment methods const methods = await getPaymentMethods(pcn, 'TRANSACTION'); // Display to user methods.data.paymentMethodsMetadata.forEach(method => { console.log(`${method.paymentMethodLabel}: ${method.totalAmount}`); }); ``` ### 2. Pre-calculate Total Amount Calculate the total amount before payment: ```javascript theme={null} const response = await getPaymentMethods(pcn); const { principal_amount, fee, tax, fx_rate } = response.data; console.log(`Amount: ${principal_amount}`); console.log(`Fee: ${fee}`); console.log(`Tax: ${tax}`); console.log(`Total: ${principal_amount + fee + tax}`); console.log(`You will receive: ${principal_amount * fx_rate}`); ``` ### 3. Check Wallet Balance Determine if customer has sufficient wallet balance: ```javascript theme={null} const methods = await getPaymentMethods(pcn); const walletMethod = methods.data.paymentMethodsMetadata .find(m => m.paymentMethod === 'E_WALLET'); if (walletMethod && walletMethod.metadata.sufficient) { // Show wallet as primary option showWalletPayment(walletMethod); } else { // Show alternative methods showOtherMethods(methods.data.paymentMethodsMetadata); } ``` # Create Investment Application Source: https://docs.fincode.technology/api/investment/create-investment-application POST /apply Creates a new investment application for a customer. Creates a new investment application allowing customers to invest in a specific investment product with a specified number of units. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. Must be `application/json`. ## Request Body The unique identifier (UUID) of the investment product to invest in. The number of units to purchase for this investment. The unique identifier (UUID) of the user wallet to use for the investment. The unique identifier (UUID) of the customer making the investment. The full name of the customer making the investment. ## Code Examples ```bash cURL theme={null} curl --location --request POST 'https://test-investment-products-service.fincode.software/api/v1/user/apply' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' \ --header 'Content-Type: application/json' \ --data '{ "investmentProductId": "123e4567-e89b-12d3-a456-426614174000", "numberOfUnitsToPurchase": 100, "userWalletId": "123e4567-e89b-12d3-a456-426614174001", "customerId": "123e4567-e89b-12d3-a456-426614174002", "customerName": "John Doe" }' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://test-investment-products-service.fincode.software/api/v1/user'; async function createInvestmentApplication(accessToken, applicationData) { try { const response = await axios.post( `${BASE_URL}/apply`, { investmentProductId: applicationData.investmentProductId, numberOfUnitsToPurchase: applicationData.numberOfUnitsToPurchase, userWalletId: applicationData.userWalletId, customerId: applicationData.customerId, customerName: applicationData.customerName, }, { headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, 'Content-Type': 'application/json', }, } ); return response.data.data; } catch (error) { console.error( 'Failed to create investment application:', error.response?.data || error.message ); throw error; } } ``` # Fund Wallet Source: https://docs.fincode.technology/api/investment/fund-wallet PUT /wallet/fund-wallet/{wallet-id}/{amount} Adds funds to a user wallet account. Adds a specified amount to a user's wallet account. This is used to fund the wallet before making investments. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the wallet to fund. The amount to add to the wallet. ## Code Examples ```bash cURL theme={null} curl --location --request PUT 'https://test-investment-products-service.fincode.software/api/v1/user/wallet/fund-wallet/123e4567-e89b-12d3-a456-426614174000/50000' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://test-investment-products-service.fincode.software/api/v1/user/wallet'; async function fundWallet(accessToken, walletId, amount) { try { const response = await axios.put( `${BASE_URL}/fund-wallet/${walletId}/${amount}`, {}, { headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); if (response.data.data) { console.log(`Wallet ${walletId} funded successfully with ${amount}`); } else { console.log('Wallet funding failed'); } return response.data.data; } catch (error) { console.error( 'Failed to fund wallet:', error.response?.data || error.message ); throw error; } } ``` # Get Investment Quote Source: https://docs.fincode.technology/api/investment/get-quote GET /quote/get-quote/{product-id}/{number-of-units-to-purchase} Retrieves a quote for purchasing a specific number of units of an investment product. Calculates and returns a quote for purchasing a specified number of units of an investment product, including the total amount, fees, and investing amount. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the investment product to get a quote for. The number of units to purchase. ## Code Examples ```bash cURL theme={null} curl --location 'https://test-investment-products-service.fincode.software/api/v1/user/quote/get-quote/123e4567-e89b-12d3-a456-426614174000/100' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://test-investment-products-service.fincode.software/api/v1/user/quote'; async function getQuote(accessToken, productId, numberOfUnits) { try { const response = await axios.get( `${BASE_URL}/get-quote/${productId}/${numberOfUnits}`, { headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); const quote = response.data.data; console.log('Quote Details:'); console.log(`Total Amount: ${quote.totalAmount}`); console.log(`Investing Amount: ${quote.investingAmount}`); console.log(`Fee Amount: ${quote.feeAmount}`); return quote; } catch (error) { console.error( 'Failed to get quote:', error.response?.data || error.message ); throw error; } } // Usage Example const accessToken = 'YOUR_JWT_ACCESS_TOKEN'; const productId = '123e4567-e89b-12d3-a456-426614174000'; getQuote(accessToken, productId, 100); ``` # Get Total Investments Source: https://docs.fincode.technology/api/investment/get-total-investments GET /get-total/{user-id} Retrieves dashboard information including total investments and interest accrued for a user. Fetches comprehensive dashboard information for a user, including their total investments across all products and the total interest accrued. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the user whose investment dashboard information to retrieve. ## Code Examples ```bash cURL theme={null} curl --location 'https://test-investment-products-service.fincode.software/api/v1/user/get-total/123e4567-e89b-12d3-a456-426614174000' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://test-investment-products-service.fincode.software/api/v1/user'; async function getTotalInvestments(accessToken, userId) { try { const response = await axios.get( `${BASE_URL}/get-total/${userId}`, { headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); const dashboard = response.data.data; console.log('Total Investments:', dashboard.totalInvestmentsResponseDto.totalInvestments); console.log('Interest Accrued:', dashboard.interestAccruedResponseDto.totalInvestments); return dashboard; } catch (error) { console.error( 'Failed to fetch total investments:', error.response?.data || error.message ); throw error; } } ``` # List Customer Portfolios Source: https://docs.fincode.technology/api/investment/list-portfolios GET /portfolios/{customer-id} Retrieves a paginated list of all investment portfolios for a customer. Fetches all investment portfolios associated with a customer, including details about each investment such as amount invested, total payable, and product information. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the customer whose portfolios to retrieve. ## Query Parameters Page number for pagination (starts from 1). Number of items per page (maximum recommended: 50). ## Code Examples ```bash cURL theme={null} curl --location 'https://test-investment-products-service.fincode.software/api/v1/user/portfolios/123e4567-e89b-12d3-a456-426614174000?page=1&size=10' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://test-investment-products-service.fincode.software/api/v1/user'; async function listPortfolios(accessToken, customerId, page = 1, size = 10) { try { const response = await axios.get( `${BASE_URL}/portfolios/${customerId}`, { params: { page, size, }, headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); const portfolios = response.data.data; console.log(`Found ${portfolios.length} portfolios`); portfolios.forEach((portfolio) => { console.log( `- ${portfolio.productName}: ${portfolio.amountInvested} ` + `(APY: ${portfolio.annualPercentageYield}%)` ); }); return portfolios; } catch (error) { console.error( 'Failed to fetch portfolios:', error.response?.data || error.message ); throw error; } } ``` # Account Balance Source: https://docs.fincode.technology/api/ledger/account-balance GET /ledger/account-balance/{account_id} Retrieves the current balance and account details for a specific account. Fetches comprehensive account balance information including available balance, account balance, account status, and account details. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the account to query. ## Code Examples ```bash cURL theme={null} curl --location 'https://{domain}.fincode.software/api/v6/services/ledger/account-balance/123e4567-e89b-12d3-a456-426614174000' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{domain}.fincode.software/api/v6/services/ledger'; async function getAccountBalance(accessToken, accountId) { try { const response = await axios.get( `${BASE_URL}/account-balance/${accountId}`, { headers: { 'X-Auth-Token': accessToken, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); const balance = response.data.data; console.log('Account Balance:', balance.accountBalance); console.log('Available Balance:', balance.availableBalance); console.log('Currency:', balance.currencyCode); console.log('Status:', balance.accountStatus); return balance; } catch (error) { console.error( 'Failed to fetch account balance:', error.response?.data || error.message ); throw error; } } ``` # Change Account Permission Source: https://docs.fincode.technology/api/ledger/change-account-permission GET /account-maintenance/change-account-permission/{id}/{permission} Changes the permission level for a specific account. Updates the account permission, allowing customers to control access and transaction capabilities for their accounts. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the account to update permissions for. The new permission level to set for the account. Valid values depend on the account permission enum. ## Code Examples ```bash cURL theme={null} curl --location 'https://{domain}.fincode.software/api/v6/services/account-maintenance/change-account-permission/123e4567-e89b-12d3-a456-426614174000/READ_ONLY' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{domain}.fincode.software/api/v6/services/account-maintenance'; async function changeAccountPermission(accessToken, accountId, permission) { try { const response = await axios.get( `${BASE_URL}/change-account-permission/${accountId}/${permission}`, { headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); console.log('Account permission updated:', response.data.data); return response.data.data; } catch (error) { console.error( 'Failed to change account permission:', error.response?.data || error.message ); throw error; } } ``` # Ledger History Source: https://docs.fincode.technology/api/ledger/ledger-history GET /ledger/account-ledger-history/{account_id}/{page}/{size} Retrieves paginated transaction history for a specific account. Fetches a paginated list of all ledger entries (transactions) for an account, providing a complete audit trail of account movements. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the account to retrieve history for. Page number for pagination (starts from 0 or 1, depending on implementation). Number of items per page. ## Code Examples ```bash cURL theme={null} curl --location 'https://{domain}.fincode.software/api/v6/services/ledger/account-ledger-history/123e4567-e89b-12d3-a456-426614174000/0/10' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{domain}.fincode.software/api/v6/services/ledger'; async function getLedgerHistory(accessToken, accountId, page = 0, size = 10) { try { const response = await axios.get( `${BASE_URL}/account-ledger-history/${accountId}/${page}/${size}`, { headers: { 'X-Auth-Token': accessToken, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); console.log(`Found ${response.data.data.length} transactions:`); response.data.data.forEach((entry) => { console.log( `${entry.executionDate}: ${entry.ledgerType} ` + `${entry.transactionAmount} (Balance: ${entry.newBalance})` ); }); return response.data.data; } catch (error) { console.error( 'Failed to fetch ledger history:', error.response?.data || error.message ); throw error; } } ``` # Ledger History by Idempotency Key Source: https://docs.fincode.technology/api/ledger/ledger-history-idempotency-key GET /ledger/account-ledger-history-idempotencykey Retrieves ledger entries matching a specific idempotency key. Fetches all ledger entries that were processed with a specific idempotency key. This is useful for retrieving all transactions related to a single idempotent request. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. The idempotency key to search for. This should be a UUID. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. ## Code Examples ```bash cURL theme={null} curl --location 'https://{domain}.fincode.software/api/v6/services/ledger/account-ledger-history-idempotencykey' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: 123e4567-e89b-12d3-a456-426614174000' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{domain}.fincode.software/api/v6/services/ledger'; async function getLedgerHistoryByIdempotencyKey(accessToken, idempotencyKey) { try { const response = await axios.get( `${BASE_URL}/account-ledger-history-idempotencykey`, { headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': idempotencyKey, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', }, } ); console.log(`Found ${response.data.data.length} transactions with idempotency key ${idempotencyKey}:`); response.data.data.forEach((entry) => { console.log( `${entry.executionDate}: ${entry.ledgerType} ` + `${entry.transactionAmount} (Balance: ${entry.newBalance})` ); }); return response.data.data; } catch (error) { console.error( 'Failed to fetch ledger history:', error.response?.data || error.message ); throw error; } } ``` # Ledger History by ID Source: https://docs.fincode.technology/api/ledger/ledger-history-interaction-id GET /ledger/account-ledger-history-interaction-id Retrieves ledger entries matching a specific interaction ID (external correlation ID). Fetches all ledger entries that were processed with a specific interaction ID (external correlation ID). This is useful for retrieving all transactions related to a single interaction or session. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. The interaction ID (external correlation ID) to search for. This should be a UUID. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. ## Code Examples ```bash cURL theme={null} curl --location 'https://{domain}.fincode.software/api/v6/services/ledger/account-ledger-history-interaction-id' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-fapi-interaction-id: 123e4567-e89b-12d3-a456-426614174000' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{domain}.fincode.software/api/v6/services/ledger'; async function getLedgerHistoryByInteractionId(accessToken, interactionId) { try { const response = await axios.get( `${BASE_URL}/account-ledger-history-interaction-id`, { headers: { 'X-Auth-Token': accessToken, 'x-fapi-interaction-id': interactionId, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', }, } ); console.log(`Found ${response.data.data.length} transactions with interaction ID ${interactionId}:`); response.data.data.forEach((entry) => { console.log( `${entry.executionDate}: ${entry.ledgerType} ` + `${entry.transactionAmount} (Balance: ${entry.newBalance})` ); }); return response.data.data; } catch (error) { console.error( 'Failed to fetch ledger history:', error.response?.data || error.message ); throw error; } } ``` # List Accounts Source: https://docs.fincode.technology/api/ledger/list-accounts GET /account-maintenance/list-accounts/{account-owner-id} Retrieves a list of all accounts owned by a specific account owner (customer). Fetches all accounts associated with a specific account owner, allowing customers to view all their accounts in one place. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the account owner (customer) whose accounts to retrieve. ## Code Examples ```bash cURL theme={null} curl --location 'https://{domain}.fincode.software/api/v6/services/account-maintenance/list-accounts/123e4567-e89b-12d3-a456-426614174000' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{domain}.fincode.software/api/v6/services/account-maintenance'; async function listAccounts(accessToken, accountOwnerId) { try { const response = await axios.get( `${BASE_URL}/list-accounts/${accountOwnerId}`, { headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); console.log(`Found ${response.data.data.length} accounts:`); response.data.data.forEach((account) => { console.log( `${account.accountNumber}: ${account.accountName} ` + `(${account.currencyCode}) - Balance: ${account.accountBalance}` ); }); return response.data.data; } catch (error) { console.error( 'Failed to list accounts:', error.response?.data || error.message ); throw error; } } ``` # Post to Account Source: https://docs.fincode.technology/api/ledger/post-account POST /gateway/post-account Executes a double-entry transaction by debiting and crediting accounts. Processes a double-entry accounting transaction by debiting one account and crediting one or more counterparty accounts. This is the core transaction posting mechanism for the ledger engine. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. Must be `application/json`. ## Request Body The request body is an array of account posting instructions. Each instruction represents a transaction. Array of account posting instructions. Account number of the primary account involved in the transaction. Currency code for the transaction (e.g., `NGN`, `USD`, `GBP`). Direction of the transaction: * `DEBIT_PRIMARY_ACCOUNT_CREDIT_COUNTERPARTY_ACCOUNT`: Debit primary account, credit counterparty * `CREDIT_PRIMARY_ACCOUNT_DEBIT_COUNTERPARTY_ACCOUNT`: Credit primary account, debit counterparty Array of counterparty accounts to credit or debit. Account number of the counterparty account. Currency code for the counterparty account. Amount to credit or debit from the counterparty account. Optional description or narration for the transaction. Unique idempotency key for this posting instruction to prevent duplicate processing. Optional handler for insufficient fund scenarios. How to handle insufficient funds: * `ON_AVAILABLE_BALANCE`: Only use available balance * `FORCE_ON_UNARRANGED_OVERDRAFT`: Allow unarranged overdraft (requires CASHIER authority) Account ID to source overdraft funds from (if applicable). ## Code Examples ```bash cURL theme={null} curl --location --request POST 'https://{domain}.fincode.software/api/v6/services/gateway/post-account' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' \ --header 'Content-Type: application/json' \ --data '[ { "primaryAccountNumber": "1234567890", "currencyCode": "NGN", "creditDebitInstructionDirection": "DEBIT_PRIMARY_ACCOUNT_CREDIT_COUNTERPARTY_ACCOUNT", "counterParties": [ { "accountNumber": "0987654321", "currencyCode": "NGN", "amount": 5000.00, "narration": "Payment for services" } ], "instructionIdempotencykey": "unique-key-12345" } ]' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{domain}.fincode.software/api/v6/services/gateway'; async function postToAccount(accessToken, postingInstructions) { try { const response = await axios.post( `${BASE_URL}/post-account`, postingInstructions, { headers: { 'X-Auth-Token': accessToken, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, 'Content-Type': 'application/json', }, } ); response.data.data.forEach((result, index) => { console.log(`Instruction ${index + 1}:`, result.responseCode); if (result.instructions) { result.instructions.forEach((instruction) => { console.log( ` Account ${instruction.accountNumber}: ` + `${instruction.amount} (New Balance: ${instruction.newBalance})` ); }); } }); return response.data.data; } catch (error) { console.error( 'Failed to post to account:', error.response?.data || error.message ); throw error; } } ``` # Accept Loan Offer Source: https://docs.fincode.technology/api/lending/accept-loan-offer PUT /user/accept-loan-offer/{loanApplicationId}/accept Accepts the loan offer. Allows the customer to accept the loan offer. This action typically triggers the next steps in the loan process. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. Must be `application/json`. ## Path Parameters The unique identifier of the loan application. # Accept Loan Terms Source: https://docs.fincode.technology/api/lending/accept-loan-terms PUT /user/accept-terms-and-conditions/{loanApplicationId} Allows customers to accept loan terms and conditions, which triggers automatic loan disbursement. This endpoint runs when customers accept the terms and conditions for an approved loan offer. Upon acceptance, the loan is automatically disbursed to the customer. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. Must be `application/json`. ## Path Parameters The unique identifier (UUID) of the loan application for which terms are being accepted. ## Code Examples ```bash cURL theme={null} curl --location --request PUT 'https://{your-domain}.fincode.software/api/v1/services/user/accept-terms-and-conditions/123e4567-e89b-12d3-a456-426614174000' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v1/services/user'; async function acceptTermsAndConditions(accessToken, loanApplicationId) { try { const response = await axios.put( `${BASE_URL}/accept-terms-and-conditions/${loanApplicationId}`, {}, { headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); return response.data.data; } catch (error) { console.error( 'Failed to accept terms and conditions:', error.response?.data || error.message ); throw error; } } ``` # Add Bank Account Source: https://docs.fincode.technology/api/lending/add-bank-account POST https://{your-domain}.fincode.software/api/v1/services/user/create-bank-account Allows customers to add a bank account to their profile for loan disbursements and repayments. Customers can use this endpoint to register a bank account that can be used for loan disbursements, repayments, and fund transfers. ```bash cURL POST theme={null} https://{your-domain}.fincode.software/api/v1/services/user/create-bank-account ``` ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. Must be `application/json`. ## Request Body The unique identifier (UUID) of the customer adding the bank account. Bank account number. Name of the account holder as it appears on the bank account. Code identifying the bank. Name of the bank. Type of account (e.g., `SAVINGS`, `CURRENT`, `CHECKING`). Whether this should be set as the default bank account. ## Response Returns confirmation of bank account creation with account details. Overall status of the API request. Bank account details. Unique identifier for the bank account. Identifier of the customer. Bank account number (may be masked for security). Account holder name. Bank code. Bank name. Whether this is the default account. Whether the account has been verified. ## Code Examples ```bash cURL theme={null} curl --location --request POST 'https://{your-domain}.fincode.software/api/v1/services/user/create-bank-account' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' \ --header 'Content-Type: application/json' \ --data '{ "customerId": "123e4567-e89b-12d3-a456-426614174000", "accountNumber": "1234567890", "accountName": "John Doe", "bankCode": "058", "bankName": "Guaranty Trust Bank", "accountType": "SAVINGS", "isDefault": true }' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v1/services/user'; async function createBankAccount(accessToken, accountData) { try { const response = await axios.post( `${BASE_URL}/create-bank-account`, { customerId: accountData.customerId, accountNumber: accountData.accountNumber, accountName: accountData.accountName, bankCode: accountData.bankCode, bankName: accountData.bankName, accountType: accountData.accountType || 'SAVINGS', isDefault: accountData.isDefault || false, }, { headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, 'Content-Type': 'application/json', }, } ); return response.data.data; } catch (error) { console.error( 'Failed to create bank account:', error.response?.data || error.message ); throw error; } } // Usage Example const accessToken = 'YOUR_JWT_ACCESS_TOKEN'; createBankAccount(accessToken, { customerId: '123e4567-e89b-12d3-a456-426614174000', accountNumber: '1234567890', accountName: 'John Doe', bankCode: '058', bankName: 'Guaranty Trust Bank', accountType: 'SAVINGS', isDefault: true, }); ``` # Calculate APR Source: https://docs.fincode.technology/api/lending/calculate-apr POST https://{your-domain}.fincode.software/api/v1/services/user/calculate-apr Calculates the Annual Percentage Rate (APR) for a loan application based on the loan amount, interest rate, and fees. Calculates the APR for a loan application, providing customers with a clear understanding of the total cost of borrowing including interest and fees. ```bash cURL POST theme={null} https://{your-domain}.fincode.software/api/v1/services/user/calculate-apr ``` ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. Must be `application/json`. ## Request Body The loan amount for which to calculate APR. Annual interest rate (as a percentage, e.g., 12.5 for 12.5%). Loan tenure in months. Processing fee amount (if applicable). Array of other fees applicable to the loan. Optional loan product ID to use product-specific fee structure. ## Response Returns the calculated APR and related cost information. Overall status of the API request. APR calculation results. Calculated Annual Percentage Rate. Total interest amount over the loan tenure. Total fees applicable to the loan. Total amount to be repaid (principal + interest + fees). Estimated monthly payment amount. Detailed breakdown of costs and payments. ## Code Examples ```bash cURL theme={null} curl --location --request POST 'https://{your-domain}.fincode.software/api/v1/services/user/calculate-apr' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' \ --header 'Content-Type: application/json' \ --data '{ "loanAmount": 50000, "interestRate": 12.5, "tenure": 12, "processingFee": 500, "loanProductId": "123e4567-e89b-12d3-a456-426614174000" }' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v1/services/user'; async function calculateAPR(accessToken, aprData) { try { const response = await axios.post( `${BASE_URL}/calculate-apr`, { loanAmount: aprData.loanAmount, interestRate: aprData.interestRate, tenure: aprData.tenure, processingFee: aprData.processingFee || 0, otherFees: aprData.otherFees || [], loanProductId: aprData.loanProductId, }, { headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, 'Content-Type': 'application/json', }, } ); return result; } catch (error) { console.error( 'Failed to calculate APR:', error.response?.data || error.message ); throw error; } } // Usage Example const accessToken = 'YOUR_JWT_ACCESS_TOKEN'; calculateAPR(accessToken, { loanAmount: 50000, interestRate: 12.5, tenure: 12, processingFee: 500, loanProductId: '123e4567-e89b-12d3-a456-426614174000', }); ``` # Get Application Source: https://docs.fincode.technology/api/lending/get-application GET /admin/loan-application/{loan-application-id} Retrieves detailed information about a specific loan application by its ID. Fetches comprehensive details of a loan application including customer information, loan terms, status, eligibility answers, and related data. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the loan application to retrieve. ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v6/services/admin/loan-application/123e4567-e89b-12d3-a456-426614174000' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v6/services/admin/loan-application'; async function getLoanApplication(accessToken, loanApplicationId) { try { const response = await axios.get( `${BASE_URL}/${loanApplicationId}`, { headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); console.log('Loan Application Details:', response.data.data); return response.data.data; } catch (error) { console.error( 'Failed to fetch loan application:', error.response?.data || error.message ); throw error; } } ``` # Available Banks Source: https://docs.fincode.technology/api/lending/get-available-banks GET /user/get-available-banks/ Retrieves a list of all available banks that customers can use for transfers and account registration. Fetches all banks that are supported for bank account registration, fund transfers, and loan disbursements. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. # Loan History Source: https://docs.fincode.technology/api/lending/get-loan-history GET /user/get-loan-history/{customerId} Retrieves a paginated history of all loans for a customer, including active, completed, and cancelled loans. Fetches a comprehensive, paginated history of all loans associated with a customer, providing detailed information about each loan's status, amounts, and timeline. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the customer whose loan history to retrieve. ## Query Parameters Page number for pagination (starts from 1). Number of items per page (maximum recommended: 50). ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v1/services/user/loan-history/123e4567-e89b-12d3-a456-426614174000?page=1&size=10' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v1/services/user'; async function getCustomerLoanHistory(accessToken, customerId, page = 1, size = 10) { try { const response = await axios.get( `${BASE_URL}/loan-history/${customerId}`, { params: { page, size, }, headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); loans.forEach((loan) => { console.log( `- ${loan.loanApplicationId}: ${loan.loanProductName} - ` + `${loan.loanAmount} (Status: ${loan.status})` ); }); return history; } catch (error) { console.error( 'Failed to fetch customer loan history:', error.response?.data || error.message ); throw error; } } ``` # Get Loan Offer Source: https://docs.fincode.technology/api/lending/get-loan-offer GET /user/get-loan-offer Retrieves the current loan offer for the customer. Returns the loan offer details made to the customer after the underwriting process. The offer may differ from the requested amount. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. # Get Loan Terms Source: https://docs.fincode.technology/api/lending/get-loan-terms GET https://{your-domain}.fincode.software/api/v1/services/user/get-loan-terms/{organisationId} Retrieves the loan terms and conditions for a specific organization. Fetches the loan terms and conditions, including interest rates, fees, repayment schedules, and other important terms that apply to loans from a specific organization. ```bash cURL GET theme={null} https://{your-domain}.fincode.software/api/v1/services/user/get-loan-terms/{organisationId} ``` ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the organization whose loan terms to retrieve. ## Response Returns the loan terms and conditions for the organization. Overall status of the API request. Loan terms and conditions details. Unique identifier of the organization. Full text of the terms and conditions. Range of interest rates applicable. Details of fees applicable to loans. Information about repayment schedules and options. Criteria that customers must meet to qualify for loans. Date when the terms were last updated. ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v1/services/user/get-loan-terms/123e4567-e89b-12d3-a456-426614174000' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v1/services/user'; async function getLoanTerms(accessToken, organisationId) { try { const response = await axios.get( `${BASE_URL}/get-loan-terms/${organisationId}`, { headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); return terms; } catch (error) { console.error( 'Failed to fetch loan terms:', error.response?.data || error.message ); throw error; } } // Usage Example const accessToken = 'YOUR_JWT_ACCESS_TOKEN'; const organisationId = '123e4567-e89b-12d3-a456-426614174000'; getLoanTerms(accessToken, organisationId); ``` # Customers Total Loan Source: https://docs.fincode.technology/api/lending/get-total-loan GET /user/get-total/{customerId} Retrieves dashboard summary information including total borrowed amounts for a user. Fetches aggregated loan information for the user's dashboard, including total amounts borrowed, outstanding balances, and other summary statistics. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the user whose dashboard totals to retrieve. # List Bank Accounts Source: https://docs.fincode.technology/api/lending/list-customer-bank-accounts GET /user/list-customer-bank-accounts/{customerId} Retrieves a list of saved bank accounts for the customer. Returns the list of bank accounts associated with the customer, which can be used for withdrawing disbursed loans. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier of the customer. # List Customer Repayments Source: https://docs.fincode.technology/api/lending/list-customer-repayments GET https://{your-domain}.fincode.software/api/v1/services/user/list-customer-repayments/{customer-id} Retrieves a list of all repayments for a specific customer across all their loans. Fetches all repayment records associated with a customer, providing details about each repayment including amounts, due dates, installment information, and balances. ```bash cURL GET theme={null} https://{your-domain}.fincode.software/api/v1/services/user/list-customer-repayments/{customer-id} ``` ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the customer whose repayments to retrieve. ## Response Returns a list of all repayments for the customer. Overall status of the API request. List of repayment records. Unique identifier of the repayment record. Repayment method (e.g., `External Bank Transfer`, `Internal Bank Transfer`). Name of the account product. Name of the customer. Customer's email address. Amount of the repayment. Name of the loan product. Outstanding principal balance. Total outstanding balance. Whether the loan amount has been fully paid. Date when the repayment record was created. Date when the payment is due. Installment number for this repayment. Unique identifier of the loan account. Unique identifier of the loan application. Total amount payable for this repayment. ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v1/services/user/list-customer-repayments/123e4567-e89b-12d3-a456-426614174000' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v1/services/user'; async function getCustomerRepayments(accessToken, customerId) { try { const response = await axios.get( `${BASE_URL}/list-customer-repayments/${customerId}`, { headers: { 'X-Auth-Token': accessToken, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); console.log(`Found ${response.data.data.length} repayments:`); response.data.data.forEach((repayment) => { console.log( `- ${repayment.loanProductName}: ${repayment.repaymentAmount} ` + `(Due: ${repayment.paymentDueDate}, Installment: ${repayment.installmentCount})` ); }); return response.data.data; } catch (error) { console.error( 'Failed to fetch customer repayments:', error.response?.data || error.message ); throw error; } } // Usage Example const accessToken = 'YOUR_JWT_ACCESS_TOKEN'; const customerId = '123e4567-e89b-12d3-a456-426614174000'; getCustomerRepayments(accessToken, customerId); ``` # List Loan Products Source: https://docs.fincode.technology/api/lending/list-products GET /user/list-products Retrieves a list of all activated loan products available to customers. Fetches all active loan products that customers can apply for, including product details, interest rates, tenure options, and eligibility requirements. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. # List Repayments Source: https://docs.fincode.technology/api/lending/list-repayments GET /admin/repayments/list Retrieves a paginated list of all repayments for a loan or across all loans. Fetches a paginated list of repayment records, allowing managers to view and track all loan repayments. Can be filtered by loan application ID to show repayments for a specific loan. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Query Parameters Optional filter to show repayments for a specific loan application. Optional filter by repayment status. Options: `PENDING_VERIFICATION`, `VERIFIED`, `REJECTED`, `ALL`. Page number for pagination (starts from 1). Number of items per page (maximum recommended: 50). Optional start date filter (ISO 8601 format) to show repayments from a specific date. Optional end date filter (ISO 8601 format) to show repayments up to a specific date. ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v6/services/admin/repayments/list?page=1&size=10&status=VERIFIED' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v6/services/admin/repayments'; async function listRepayments(accessToken, filters = {}) { try { const params = { page: filters.page || 1, size: filters.size || 10, }; if (filters.loanApplicationId) { params.loanApplicationId = filters.loanApplicationId; } if (filters.status) { params.status = filters.status; } if (filters.startDate) { params.startDate = filters.startDate; } if (filters.endDate) { params.endDate = filters.endDate; } const response = await axios.get(`${BASE_URL}/list`, { params, headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, }); const repayments = response.data.data.content; console.log(`Found ${repayments.length} repayments`); console.log(`Total: ${response.data.data.totalElements} repayments`); console.log(`Page ${response.data.data.currentPage} of ${response.data.data.totalPages}`); repayments.forEach((repayment) => { console.log( `- ${repayment.repaymentId}: ${repayment.repaymentAmount} ` + `(${repayment.paymentMethod}) - Status: ${repayment.status}` ); }); return response.data.data; } catch (error) { console.error( 'Failed to list repayments:', error.response?.data || error.message ); throw error; } } ``` # Loan Application Details Source: https://docs.fincode.technology/api/lending/loan-application-details GET https://{your-domain}.fincode.software/api/v1/services/user/loan-application-details/{loan-application-id} Retrieves comprehensive details of a loan application including full application information and loan product name. Fetches detailed information about a loan application including all application fields, customer information, loan terms, and the associated loan product name. ```bash cURL GET theme={null} https://{your-domain}.fincode.software/api/v1/services/user/loan-application-details/{loan-application-id} ``` ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the loan application to retrieve. ## Response Returns comprehensive loan application details including full application information and loan product name. Overall status of the API request. Response object containing loan details and product name. Complete loan application details. Unique identifier of the loan application. Date when the loan application was created. Unique identifier of the user who requested the loan. Unique identifier of the loan product. Unique identifier of the organisation. Current status of the loan application (e.g., `REQUESTED`, `APPROVED`, `OFFER_SENT`, `ACCEPTED`, `DISBURSED`). The loan amount requested by the customer. Loan duration. Repayment method (e.g., `External Bank Transfer`, `Internal Bank Transfer`). Unique identifier of the customer's credit account. Customer's employment status. Customer's monthly income. Currency code with symbol (e.g., `NGN (₦)`). Duration counter unit (e.g., `MONTH`, `WEEK`, `DAY`). Customer's name. Customer's email address. Loan application identifier. Customer's phone number. Customer's date of birth. Name of the loan product associated with this application. ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v1/services/user/loan-application-details/123e4567-e89b-12d3-a456-426614174000' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v1/services/user'; async function getLoanApplicationDetails(accessToken, loanApplicationId) { try { const response = await axios.get( `${BASE_URL}/loan-application-details/${loanApplicationId}`, { headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); const { loanDetails, loanProductName } = response.data.data; console.log('Loan Product:', loanProductName); console.log('Application Status:', loanDetails.loanApplicationStatusEnum); console.log('Requested Amount:', loanDetails.requestedLoanAmount); console.log('Customer:', loanDetails.customerName); return response.data.data; } catch (error) { console.error( 'Failed to fetch loan application details:', error.response?.data || error.message ); throw error; } } // Usage Example const accessToken = 'YOUR_JWT_ACCESS_TOKEN'; const loanApplicationId = '123e4567-e89b-12d3-a456-426614174000'; getLoanApplicationDetails(accessToken, loanApplicationId); ``` # Loan Details with Payment History Source: https://docs.fincode.technology/api/lending/loan-details-with-payment-history GET https://{your-domain}.fincode.software/api/v1/services/user/loan-details-with-payment-history/{loan-application-id} Retrieves comprehensive loan application details including payment history and installment schedule. Fetches detailed information about a loan application including all installments, payment history, outstanding balances, and repayment schedule. ```bash cURL GET theme={null} https://{your-domain}.fincode.software/api/v1/services/user/loan-details-with-payment-history/{loan-application-id} ``` ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the loan application for which to retrieve details. ## Response Returns comprehensive loan details including installment schedule and payment history. Overall status of the API request. Loan application details with payment history. Unique identifier of the loan application. Unique identifier of the customer. Name of the customer. Email address of the customer. Name of the loan product. Current status of the loan application (e.g., `REQUESTED`, `APPROVED`, `DISBURSED`). Account state (e.g., `ACTIVE`, `CLOSED`, `ACTIVE_IN_ARREARS`). Original loan amount (principal). Interest rate applicable to the loan. Total repayment amount (principal + total interest + fees). Total outstanding balance. Outstanding principal balance. Outstanding interest balance. Outstanding fees balance. Outstanding penalty balance. Total amount paid so far. Principal amount paid. Interest amount paid. Fees amount paid. Penalty amount paid. Date when the loan application was created. Date when the loan was disbursed. Date of the first installment. Loan maturity date. Next payment due date. Total number of installments. Number of installments paid. Number of installments remaining. Loan duration. Duration counter unit (e.g., `MONTH`, `WEEK`, `DAY`). Loan repayment method (e.g., `External Bank Transfer`, `Internal Bank Transfer`). Whether the loan uses third-party payment collection (e.g., Remita). Bank name for manual repayments. Account number for manual repayments. Account name for manual repayments. Whether the loan is fully repaid. Currency code. List of all installments with payment details. Installment number (1, 2, 3, etc.). Due date for this installment. Total installment amount (principal + interest + fees). Principal amount for this installment. Interest amount for this installment. Fees amount for this installment. Penalty amount (if any). Amount paid for this installment. Outstanding amount for this installment. Payment status (e.g., `PENDING`, `PAID`, `PARTIAL`, `OVERDUE`). Date when payment was made (if paid). Number of days overdue (if applicable). ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v1/services/user/loan-details-with-payment-history/123e4567-e89b-12d3-a456-426614174000' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v1/services/user'; async function getLoanDetailsWithPaymentHistory(accessToken, loanApplicationId) { try { const response = await axios.get( `${BASE_URL}/loan-details-with-payment-history/${loanApplicationId}`, { headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); const loanDetails = response.data.data; console.log('Loan Details:'); console.log(`- Application ID: ${loanDetails.loanApplicationId}`); console.log(`- Product: ${loanDetails.loanProductName}`); console.log(`- Total Installments: ${loanDetails.totalInstallments}`); console.log(`- Installments Paid: ${loanDetails.installmentsPaid}`); console.log(`- Total Balance: ${loanDetails.totalBalance}`); console.log(`- Next Payment Due: ${loanDetails.nextPaymentDueDate}`); console.log('\nInstallment Schedule:'); loanDetails.paymentHistory.forEach((installment) => { console.log( `Installment ${installment.installmentNumber}: ` + `${installment.installmentAmount} due ${installment.dueDate} ` + `(Status: ${installment.paymentStatus})` ); }); return loanDetails; } catch (error) { console.error( 'Failed to fetch loan details:', error.response?.data || error.message ); throw error; } } // Usage Example const accessToken = 'YOUR_JWT_ACCESS_TOKEN'; const loanApplicationId = '123e4567-e89b-12d3-a456-426614174000'; getLoanDetailsWithPaymentHistory(accessToken, loanApplicationId); ``` # Eligibility Questions Source: https://docs.fincode.technology/api/lending/loan-eligibility-questions GET /user/loan-eligibility-questions/{productId} Retrieves the eligibility questions required for a specific loan product. Fetches all eligibility questions that customers need to answer when applying for a specific loan product. These questions are used to determine if the customer meets the product's eligibility criteria. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the loan product whose eligibility questions to retrieve. # Request Loan Source: https://docs.fincode.technology/api/lending/loan-request POST /user/request-loan Creates a new loan application request from a customer or agent. Creates a new loan application request. Customers or agents can use this endpoint to submit loan applications with required details including loan amount, product selection, and eligibility information. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. Must be `application/json`. ## Request Body The currency code for the loan (e.g., "NGN"). Customer's date of birth (YYYY-MM-DD). The numeric value of the duration (e.g., 12). Initial status of the application. Must be "REQUESTED". Customer's employment status (e.g., "EMPLOYED", "SELF\_EMPLOYED"). The requested loan amount. Bank Verification Number of the customer. Customer's first name. Customer's last name. Bank account number for disbursement/repayment. Code of the bank associated with the account number. Customer's phone number. Duration of the loan. The unique identifier of the loan product. Method of repayment (e.g., "DIRECT\_DEBIT"). Customer's monthly income. Array of answers to eligibility questions. Unique identifier of the eligibility question. Answer to the eligibility question. ## Code Examples ```bash cURL theme={null} curl --location --request POST 'https://{your-domain}.fincode.software/api/v6/services/user/request-loan' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' \ --header 'Content-Type: application/json' \ --data '{ "currencyCode": "NGN", "dateOfBirth": "1990-01-01", "durationCounter": 12, "loanApplicationStatusEnum": "REQUESTED", "employmentStatus": "EMPLOYED", "loanAmount": 50000.00, "bvn": "12345678901", "firstName": "John", "lastName": "Doe", "accountNumber": "0123456789", "bankCode": "044", "phoneNumber": "08012345678", "loanDuration": 12, "loanProductId": "product-123", "loanRepaymentMethodEnum": "DIRECT_DEBIT", "monthlyIncome": 150000.00, "eligibilityAnswers": [ { "questionId": "q1", "answer": "Yes" } ] }' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v6/services/user'; async function requestLoan(accessToken, loanRequestData) { try { const response = await axios.post( `${BASE_URL}/request-loan`, { customerId: loanRequestData.customerId, loanProductId: loanRequestData.loanProductId, requestedAmount: loanRequestData.requestedAmount, purpose: loanRequestData.purpose || 'PERSONAL', tenurePreference: loanRequestData.tenurePreference, eligibilityAnswers: loanRequestData.eligibilityAnswers || [], additionalNotes: loanRequestData.additionalNotes || '', }, { headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, 'Content-Type': 'application/json', }, } ); console.log('Loan application created successfully!'); console.log('Application ID:', response.data.data.loanApplicationId); console.log('Status:', response.data.data.status); console.log('Requested Amount:', response.data.data.requestedAmount); if (response.data.data.nextSteps && response.data.data.nextSteps.length > 0) { console.log('\nNext Steps:'); response.data.data.nextSteps.forEach((step, index) => { console.log(` ${index + 1}. ${step}`); }); } return response.data.data; } catch (error) { console.error( 'Failed to create loan application:', error.response?.data || error.message ); throw error; } } ``` # Manage Loans Source: https://docs.fincode.technology/api/lending/manage-loans GET /user/manage-loans/{customerId} Retrieves active loans that are due for repayment. Returns details of loans that are currently active and may require repayment management. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier of the customer. # Payoff Loan Source: https://docs.fincode.technology/api/lending/payoff-loan POST https://{your-domain}.fincode.software/api/v1/services/user/payoff-loan Allows customers to pay off their entire loan balance in a single transaction. Customers can use this endpoint to settle their loan completely by paying the remaining outstanding balance in one transaction. ```bash cURL POST theme={null} https://{your-domain}.fincode.software/api/v1/services/user/payoff-loan ``` ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. Must be `application/json`. ## Request Body The unique identifier (UUID) of the loan application to pay off. Method of payment. Options: `WALLET`, `BANK_TRANSFER`, `CARD`, etc. Transaction PIN for authorization (if required). Optional payoff amount. If not provided, the system will calculate the full outstanding balance. ## Response Returns confirmation of the loan payoff with final settlement details. Overall status of the API request. Payoff confirmation details. Unique identifier for the payoff transaction. Identifier of the loan application. The amount that was paid to settle the loan. Remaining balance after payoff (should be 0). Updated status of the loan (should be `PAID_OFF` or `COMPLETED`). Reference number for the payoff transaction. Date and time when the loan was paid off. ## Code Examples ```bash cURL theme={null} curl --location --request POST 'https://{your-domain}.fincode.software/api/v1/services/user/payoff-loan' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' \ --header 'Content-Type: application/json' \ --data '{ "loanApplicationId": "123e4567-e89b-12d3-a456-426614174000", "paymentMethod": "WALLET", "transactionPin": "1234" }' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v1/services/user'; async function payoffLoan(accessToken, payoffData) { try { const response = await axios.post( `${BASE_URL}/payoff-loan`, { loanApplicationId: payoffData.loanApplicationId, paymentMethod: payoffData.paymentMethod, transactionPin: payoffData.transactionPin, payoffAmount: payoffData.payoffAmount, }, { headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, 'Content-Type': 'application/json', }, } ); return response.data.data; } catch (error) { console.error( 'Failed to payoff loan:', error.response?.data || error.message ); throw error; } } // Usage Example const accessToken = 'YOUR_JWT_ACCESS_TOKEN'; payoffLoan(accessToken, { loanApplicationId: '123e4567-e89b-12d3-a456-426614174000', paymentMethod: 'WALLET', transactionPin: '1234', }); ``` # Pending Repayments Source: https://docs.fincode.technology/api/lending/pending-repayments GET https://{your-domain}.fincode.software/api/v1/services/user/pending-repayments/{user-id} Retrieves a paginated list of pending repayments for a user across all their loans. Fetches all pending repayments that the user needs to make, including due dates and amounts for each installment. ```bash cURL GET theme={null} https://{your-domain}.fincode.software/api/v1/services/user/pending-repayments/{user-id} ``` ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the user whose pending repayments to retrieve. ## Query Parameters Page number for pagination (starts from 1). Number of items per page (maximum recommended: 50). ## Response Returns a list of pending repayments with details. Overall status of the API request. Array of pending repayment objects. Unique identifier for the loan application. Sequential number of the installment. Date when this repayment is due. Amount that needs to be repaid. Principal portion of the repayment. Interest portion of the repayment. Status of the repayment (e.g., `PENDING`, `OVERDUE`). Number of days the repayment is overdue (if applicable). ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v1/services/user/pending-repayments/123e4567-e89b-12d3-a456-426614174000?page=1&size=10' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v1/services/user'; async function getPendingRepayments(accessToken, userId, page = 1, size = 10) { try { const response = await axios.get( `${BASE_URL}/pending-repayments/${userId}`, { params: { page, size, }, headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); repayments.forEach((repayment) => { console.log( `- Loan ${repayment.loanApplicationId}: ` + `${repayment.amountDue} due ${repayment.dueDate} ` + `(Status: ${repayment.status})` ); }); return repayments; } catch (error) { console.error( 'Failed to fetch pending repayments:', error.response?.data || error.message ); throw error; } } // Usage Example const accessToken = 'YOUR_JWT_ACCESS_TOKEN'; const userId = '123e4567-e89b-12d3-a456-426614174000'; getPendingRepayments(accessToken, userId, 1, 20); ``` # Reject Loan Offer Source: https://docs.fincode.technology/api/lending/reject-loan-offer PUT /user/accept-loan-offer/{loanApplicationId}/reject Rejects the loan offer. Allows the customer to reject the loan offer. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. Must be `application/json`. ## Path Parameters The unique identifier of the loan application. # Repaid Transactions Source: https://docs.fincode.technology/api/lending/repaid-transactions GET https://{your-domain}.fincode.software/api/v1/services/user/repaid-transactions/{user-id} Retrieves a list of all repaid transactions for a user. Fetches all repayment transactions that have been completed by the user across all their loans. ```bash cURL GET theme={null} https://{your-domain}.fincode.software/api/v1/services/user/repaid-transactions/{user-id} ``` ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the user whose repaid transactions to retrieve. ## Response Returns a list of all repaid transactions. Overall status of the API request. Array of repayment transaction objects. Unique identifier for the repayment. Identifier of the loan application. Amount that was repaid. Date when the payment was made. Method used for payment. Status of the repayment (typically `VERIFIED` or `PAID`). ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v1/services/user/repaid-transactions/123e4567-e89b-12d3-a456-426614174000' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v1/services/user'; async function getRepaidTransactions(accessToken, userId) { try { const response = await axios.get( `${BASE_URL}/repaid-transactions/${userId}`, { headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); return transactions; } catch (error) { console.error( 'Failed to fetch repaid transactions:', error.response?.data || error.message ); throw error; } } ``` # Repay Loan Source: https://docs.fincode.technology/api/lending/repay-loan POST https://{your-domain}.fincode.software/api/v1/services/user/repay-loan/{user-id} Allows customers to make a partial repayment for their loan. Customers can use this endpoint to record a partial repayment for their loan. This is typically used after making a bank transfer to the repayment account. ```bash cURL POST theme={null} https://{your-domain}.fincode.software/api/v1/services/user/repay-loan/{user-id} ``` Before making a repayment, customers should: 1. Get repayment instructions using `GET /repayment-instructions/{loan-application-id}` 2. Make a bank transfer to the provided account with the repayment reference 3. Record the repayment using this endpoint Some loans use third-party collection services. Manual repayments via this API may not be allowed for such loans. The system will return an error if manual repayment is not permitted. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. Must be `application/json`. ## Path Parameters The unique identifier (UUID) of the user making the repayment. This must match the authenticated user. ## Request Body The amount to be repaid. Must be greater than zero and cannot exceed the total payable amount. The unique identifier (UUID) of the customer making the repayment. Must match the authenticated user. The unique identifier (UUID) of the loan account being repaid. The unique identifier (UUID) of the bank account from which the payment was made. This must be a bank account that belongs to the customer. The payment reference number from the bank transfer. This should match the reference provided in the repayment instructions. The date when the payment was made (ISO 8601 format). If not provided, the current date is used. Optional description or narration for the payment. ## Response Returns confirmation of the repayment submission with details. Overall status of the API request. Repayment confirmation details. Unique identifier for the repayment record. The amount that was repaid. Name of the customer who made the repayment. Email address of the customer. Name of the loan product. Payment reference number for the repayment. Status of the repayment verification. Options: `PENDING_VERIFICATION`, `VERIFIED`, `REJECTED`. Message confirming the repayment submission. ## Code Examples ```bash cURL theme={null} curl --location --request POST 'https://{your-domain}.fincode.software/api/v1/services/user/repay-loan/123e4567-e89b-12d3-a456-426614174000' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' \ --header 'Content-Type: application/json' \ --data '{ "repaymentAmount": 50000, "customerId": "123e4567-e89b-12d3-a456-426614174000", "accountId": "223e4567-e89b-12d3-a456-426614174001", "bankAccountId": "323e4567-e89b-12d3-a456-426614174002", "repaymentReference": "REF-2024-01-15-001", "paymentDate": "2024-01-15T10:00:00Z", "paymentNarration": "Monthly installment payment" }' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v1/services/user'; async function repayLoan(accessToken, userId, repaymentData) { try { const response = await axios.post( `${BASE_URL}/repay-loan/${userId}`, { repaymentAmount: repaymentData.amount, customerId: repaymentData.customerId, accountId: repaymentData.accountId, bankAccountId: repaymentData.bankAccountId, repaymentReference: repaymentData.reference, paymentDate: repaymentData.paymentDate || new Date().toISOString(), paymentNarration: repaymentData.narration, }, { headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, 'Content-Type': 'application/json', }, } ); const repayment = response.data.data; console.log('Repayment submitted successfully:'); console.log(`- Repayment ID: ${repayment.id}`); console.log(`- Amount: ${repayment.repaymentAmount}`); console.log(`- Status: ${repayment.verificationStatus}`); console.log(`- Message: ${repayment.message}`); return repayment; } catch (error) { console.error( 'Failed to submit repayment:', error.response?.data || error.message ); throw error; } } // Usage Example const accessToken = 'YOUR_JWT_ACCESS_TOKEN'; const userId = '123e4567-e89b-12d3-a456-426614174000'; // First, get repayment instructions // Then make bank transfer // Finally, record the repayment repayLoan(accessToken, userId, { amount: 50000, customerId: '123e4567-e89b-12d3-a456-426614174000', accountId: '223e4567-e89b-12d3-a456-426614174001', bankAccountId: '323e4567-e89b-12d3-a456-426614174002', reference: 'REF-2024-01-15-001', paymentDate: '2024-01-15T10:00:00Z', narration: 'Monthly installment payment', }); ``` ## Error Responses Status will be `FAILED` if an error occurs. Error message describing what went wrong. ### Common Error Scenarios * **Loan Not Found**: No active loan found for the provided customer ID * **Loan Closed**: The loan is already closed and cannot be repaid * **Unauthorized**: The customer ID does not match the authenticated user * **Manual Repayment Not Allowed**: The loan uses third-party collection and manual repayments are not permitted * **Invalid Amount**: Repayment amount is zero, negative, or exceeds total payable * **Bank Account Mismatch**: The bank account does not belong to the customer * **Missing Loan Application**: Loan application ID is missing for the customer loan record See the complete repayment flow documentation # Repayment Instructions Source: https://docs.fincode.technology/api/lending/repayment-instructions GET https://{your-domain}.fincode.software/api/v1/services/user/repayment-instructions/{loan-application-id} Retrieves detailed repayment instructions for a loan, including payment methods and account details. Fetches comprehensive repayment instructions for a loan, including bank account details, payment reference numbers, and step-by-step instructions for making repayments. ```bash cURL GET theme={null} https://{your-domain}.fincode.software/api/v1/services/user/repayment-instructions/{loan-application-id} ``` ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the loan application for which to get repayment instructions. ## Response Returns detailed repayment instructions. Overall status of the API request. Repayment instructions details. Unique identifier of the loan application. Available payment methods for repayment. Bank account details for bank transfer payments. Bank account number for repayments. Account name. Bank code. Bank name. Payment reference number to include in transfers. Step-by-step instructions for making repayments. Contact details for repayment support. ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v1/services/user/repayment-instructions/123e4567-e89b-12d3-a456-426614174000' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v1/services/user'; async function getRepaymentInstructions(accessToken, loanApplicationId) { try { const response = await axios.get( `${BASE_URL}/repayment-instructions/${loanApplicationId}`, { headers: { 'X-Auth-Token': accessToken, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); instructions.instructions.forEach((instruction, index) => { console.log(`${index + 1}. ${instruction}`); }); return instructions; } catch (error) { console.error( 'Failed to fetch repayment instructions:', error.response?.data || error.message ); throw error; } } // Usage Example const accessToken = 'YOUR_JWT_ACCESS_TOKEN'; const loanApplicationId = '123e4567-e89b-12d3-a456-426614174000'; getRepaymentInstructions(accessToken, loanApplicationId); ``` # Transfer Funds to Bank Source: https://docs.fincode.technology/api/lending/transfer-funds POST https://{your-domain}.fincode.software/api/v1/services/user/transfer-funds-to-bank Allows customers to transfer funds from their loan wallet to a bank account. Customers can use this endpoint to transfer funds from their loan wallet balance to a registered bank account. ```bash cURL POST theme={null} https://{your-domain}.fincode.software/api/v1/services/user/transfer-funds-to-bank ``` ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. Must be `application/json`. ## Request Body The unique identifier (UUID) of the customer making the transfer. Amount to transfer from wallet to bank account. The unique identifier (UUID) of the bank account to transfer funds to. Bank account number to transfer to. Bank code of the destination bank. Account holder name as it appears on the bank account. Transaction PIN for authorization (if required). Optional description or reference for the transfer. ## Response Returns confirmation of the fund transfer with transaction details. Overall status of the API request. Transfer confirmation details. Unique reference number for the transfer transaction. Unique identifier for the transfer. Amount transferred. Status of the transfer (e.g., `PENDING`, `PROCESSING`, `COMPLETED`, `FAILED`). Date and time when the transfer was initiated. Estimated time for the transfer to be completed. ## Code Examples ```bash cURL theme={null} curl --location --request POST 'https://{your-domain}.fincode.software/api/v1/services/user/transfer-funds-to-bank' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' \ --header 'Content-Type: application/json' \ --data '{ "customerId": "123e4567-e89b-12d3-a456-426614174000", "amount": 10000.00, "bankAccountId": "123e4567-e89b-12d3-a456-426614174000", "accountNumber": "1234567890", "bankCode": "058", "accountName": "John Doe", "transactionPin": "1234", "description": "Transfer to savings account" }' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v1/services/user'; async function transferFundsToBank(accessToken, transferData) { try { const response = await axios.post( `${BASE_URL}/transfer-funds-to-bank`, { customerId: transferData.customerId, amount: transferData.amount, bankAccountId: transferData.bankAccountId, accountNumber: transferData.accountNumber, bankCode: transferData.bankCode, accountName: transferData.accountName, transactionPin: transferData.transactionPin, description: transferData.description || '', }, { headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, 'Content-Type': 'application/json', }, } ); return response.data.data; } catch (error) { console.error( 'Failed to transfer funds:', error.response?.data || error.message ); throw error; } } // Usage Example const accessToken = 'YOUR_JWT_ACCESS_TOKEN'; transferFundsToBank(accessToken, { customerId: '123e4567-e89b-12d3-a456-426614174000', amount: 10000.00, bankAccountId: '123e4567-e89b-12d3-a456-426614174000', accountNumber: '1234567890', bankCode: '058', accountName: 'John Doe', transactionPin: '1234', description: 'Transfer to savings account', }); ``` # Transfer History Source: https://docs.fincode.technology/api/lending/transfer-history GET /user/transfer-history/{customerId} Retrieves the history of transfers (withdrawals) made by the customer. Returns a list of transfers initiated by the customer, typically withdrawals from their loan wallet to their bank account. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier of the customer. # Transfer Status Source: https://docs.fincode.technology/api/lending/transfer-status GET https://{your-domain}.fincode.software/api/v1/services/user/check-transfer-status/{transactionReference} Checks the settlement status of a fund transfer transaction. Allows customers to check the current status of a fund transfer transaction, including whether it has been completed, is still processing, or has failed. ```bash cURL GET theme={null} https://{your-domain}.fincode.software/api/v1/services/user/check-transfer-status/{transactionReference} ``` ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The transaction reference number of the transfer to check. ## Response Returns the current status of the transfer transaction. Overall status of the API request. Transfer status details. Transaction reference number. Current status of the transfer (e.g., `PENDING`, `PROCESSING`, `COMPLETED`, `FAILED`, `CANCELLED`). Amount of the transfer. Date and time when the transfer was initiated. Date and time when the transfer was completed (if completed). Reason for failure (if status is `FAILED`). Details about the settlement process. ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v1/services/user/check-transfer-status/TXN-20240115-001234' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v1/services/user'; async function checkTransferStatus(accessToken, transactionReference) { try { const response = await axios.get( `${BASE_URL}/check-transfer-status/${transactionReference}`, { headers: { 'X-Auth-Token': accessToken, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); if (status.completedDate) { console.log(`Completed: ${status.completedDate}`); } if (status.failureReason) { console.log(`Failure Reason: ${status.failureReason}`); } return status; } catch (error) { console.error( 'Failed to check transfer status:', error.response?.data || error.message ); throw error; } } // Usage Example const accessToken = 'YOUR_JWT_ACCESS_TOKEN'; checkTransferStatus(accessToken, 'TXN-20240115-001234'); ``` # Update Loan Offer Source: https://docs.fincode.technology/api/lending/update-application PUT https://{your-domain}.fincode.software/api/v1/services/user/update-application/{loan-application-id} Allows customers to accept or withdraw from a loan offer that has been sent to them. Customers can use this endpoint to respond to a loan offer. If the offer is accepted, the application status changes to `ACCEPTED`. If withdrawn, the status changes to `WITHDRAWN`. This endpoint can only be used when the loan application status is `OFFER_SENT`. Attempting to use it with any other status will result in an error. ```bash cURL PUT theme={null} https://{your-domain}.fincode.software/api/v1/services/user/update-application/{loan-application-id}?status=true ``` ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the loan application to update. ## Query Parameters * `true`: Accept the loan offer (status changes to `ACCEPTED`) * `false`: Withdraw from the loan offer (status changes to `WITHDRAWN`) ## Response Returns the updated loan application details. Overall status of the API request. Updated loan application details. Unique identifier of the loan application. Identifier of the loan product. Name of the customer. Name of the loan product. Currency code. Employment status of the customer. Date when the loan application was created. Unique identifier of the user. Duration counter unit (e.g., `MONTH`, `WEEK`, `DAY`). Requested loan amount. Updated loan application status (`ACCEPTED` or `WITHDRAWN`). Customer's monthly income. Customer's date of birth. Loan duration. ## Code Examples ```bash cURL theme={null} curl --location --request PUT 'https://{your-domain}.fincode.software/api/v1/services/user/update-application/123e4567-e89b-12d3-a456-426614174000?status=true' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-idempotency-key: unique-key-12345' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v1/services/user'; async function updateLoanApplicationOffer(accessToken, loanApplicationId, acceptOffer) { try { const response = await axios.put( `${BASE_URL}/update-application/${loanApplicationId}`, null, { params: { status: acceptOffer, }, headers: { 'X-Auth-Token': accessToken, 'x-idempotency-key': `key-${Date.now()}`, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); console.log('Loan offer updated:', response.data.data); return response.data.data; } catch (error) { console.error( 'Failed to update loan offer:', error.response?.data || error.message ); throw error; } } // Usage Example - Accept offer const accessToken = 'YOUR_JWT_ACCESS_TOKEN'; const loanApplicationId = '123e4567-e89b-12d3-a456-426614174000'; updateLoanApplicationOffer(accessToken, loanApplicationId, true); // Usage Example - Withdraw from offer updateLoanApplicationOffer(accessToken, loanApplicationId, false); ``` # Verify Bank Account Source: https://docs.fincode.technology/api/lending/verify-bank-account GET /user/verify-bank-account/{bankCode}/{accountNumber} Verifies a bank account number against a bank code. Verifies the provided bank account details and returns the account holder's name if valid. This is used before adding a bank account for withdrawals. ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. Unique idempotency key for the request to prevent duplicate processing. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The code of the bank (retrieved from Get Available Banks). The account number to verify. # View Bank Account Source: https://docs.fincode.technology/api/lending/view-bank-account GET https://{your-domain}.fincode.software/api/v1/services/user/view-bank-account/{account-id} Retrieves details of a specific bank account by its ID. Fetches detailed information about a bank account registered by the customer. ```bash cURL GET theme={null} https://{your-domain}.fincode.software/api/v1/services/user/view-bank-account/{account-id} ``` ## Request Headers The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. The date and time at which the request was initiated (ISO 8601 format). The IP address of the customer making the request. Unique identifier for the interaction/session. ## Path Parameters The unique identifier (UUID) of the bank account to retrieve. ## Response Returns bank account details. Overall status of the API request. Bank account details. Unique identifier for the bank account. Identifier of the customer. Bank account number (may be masked). Account holder name. Bank code. Bank name. Type of account. Whether this is the default account. Whether the account has been verified. Date when the account was added. ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v1/services/user/view-bank-account/123e4567-e89b-12d3-a456-426614174000' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'x-fapi-auth-date: 2024-01-15T10:30:00Z' \ --header 'x-fapi-customer-ip-address: 192.168.1.1' \ --header 'x-fapi-interaction-id: interaction-12345' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v1/services/user'; async function viewBankAccount(accessToken, accountId) { try { const response = await axios.get( `${BASE_URL}/view-bank-account/${accountId}`, { headers: { 'X-Auth-Token': accessToken, 'x-fapi-auth-date': new Date().toISOString(), 'x-fapi-customer-ip-address': '192.168.1.1', 'x-fapi-interaction-id': `interaction-${Date.now()}`, }, } ); return account; } catch (error) { console.error( 'Failed to fetch bank account:', error.response?.data || error.message ); throw error; } } ``` # Active Countries Source: https://docs.fincode.technology/api/security/active-countries GET /utilitiesmanagement/active-countries Retrieves the systems's saved country list. Retrieves the current list of active countries stored in the system with their various properties like country name and iso3Codes. This endpoint helps client applications for where users country is required. ## Request Headers This endpoint is typically **public** and **does not require an Access Token** for authorization, relying on the organization domain provided in the URL. Platform identifier. Use `fincode`. Unique request identifier. ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v6/services/utilitiesmanagement/active-countries' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v6/services/utilitiesmanagement'; async function viewCountryList() { try { const response = await axios.get(`${BASE_URL}/active-countries`, { headers: { platform: 'fincode', uuid: '200', }, }); return response.data; } catch (error) { console.error( 'Failed to fetch country list:', error.response?.data || error.message ); throw error; } } viewCountryList(); ``` # Fetch Preference Source: https://docs.fincode.technology/api/security/fetch-preference GET /admin/organisation-preference-management/fetch-organisaction-preference Retrieves the current system and configuration preferences for the authenticated organisation/tenant. Retrieves the global settings and configurations applied to the current organisation/tenant. This includes business rules, feature toggles, and system defaults. ## Request Headers This endpoint does NOT requires an **Access Token** for authorization, and relies on the organization domain provided by that url. Platform identifier. Use `fincode`. Unique request identifier. ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v6/services/admin/organisation-preference-management/fetch-organisaction-preference' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v6/services/admin/organisation-preference-management'; async function fetchOrganisationPreference(accessToken) { try { const response = await axios.get( `${BASE_URL}/fetch-organisaction-preference`, { headers: { 'X-Auth-Token': accessToken, platform: 'fincode', uuid: '200', }, } ); console.log('Preferences fetched successfully!'); console.log('Max Limit:', response.data.preferences.MAX_TRANSACTION_LIMIT); return response.data; } catch (error) { console.error( 'Failed to fetch preferences:', error.response?.data || error.message ); throw error; } } // Usage Example const accessToken = 'YOUR_JWT_ACCESS_TOKEN'; fetchOrganisationPreference(accessToken); ``` # List Countries Source: https://docs.fincode.technology/api/security/list-countries GET /utilitiesmanagement/list-all-countries Retrieves the systems's saved country list. Retrieves the current list of countries stored in the system with their various properties like country name and iso3Codes. This endpoint helps client applications for where users country is required. ## Request Headers This endpoint is typically **public** and **does not require an Access Token** for authorization, relying on the organization domain provided in the URL. Platform identifier. Use `fincode`. Unique request identifier. ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v6/services/utilitiesmanagement/list-all-countries' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v6/services/utilitiesmanagement'; async function viewCountryList() { try { const response = await axios.get(`${BASE_URL}/list-all-countries`, { headers: { platform: 'fincode', uuid: '200', }, }); return response.data; } catch (error) { console.error( 'Failed to fetch country list:', error.response?.data || error.message ); throw error; } } viewCountryList(); ``` # Password Policy Source: https://docs.fincode.technology/api/security/password-policy GET /admin/security/view-password-policy Retrieves the organization's current password complexity and validity rules. Retrieves the current rules and restrictions for user passwords, including minimum length, required characters, and expiration settings. This endpoint helps client applications enforce correct password creation and updates. ## Request Headers This endpoint is typically **public** and **does not require an Access Token** for authorization, relying on the organization domain provided in the URL. Platform identifier. Use `fincode`. Unique request identifier. ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v6/services/admin/security/view-password-policy' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v6/services/admin/security'; async function viewPasswordPolicy() { try { const response = await axios.get(`${BASE_URL}/view-password-policy`, { headers: { platform: 'fincode', uuid: '200', }, }); console.log('Password Policy fetched successfully!'); console.log('Minimum Length:', response.data.minimumLength); console.log('Requires Digit:', response.data.requiresDigit); return response.data; } catch (error) { console.error( 'Failed to fetch password policy:', error.response?.data || error.message ); throw error; } } viewPasswordPolicy(); ``` # Bank Account Validation Source: https://docs.fincode.technology/api/songhai-exchange/bank-account-validation POST /gateway/v2/account-number-validation Validate bank account number. # Change Password Source: https://docs.fincode.technology/api/songhai-exchange/change-password PUT /v1/services/usermanagement/change-password/{id} Change user password. # Create Transaction Source: https://docs.fincode.technology/api/songhai-exchange/create-transaction POST /gateway/transaction/banktransfers Create a bank transfer transaction. # Domiciliary Account (Account Number) Source: https://docs.fincode.technology/api/songhai-exchange/domiciliary-account-with-account-number POST /gateway/create-domiciliary-bank-account Automatically create a domiciliary account using an existing Naira account number. Only supported in Nigeria. # Domiciliary Account (BVN) Source: https://docs.fincode.technology/api/songhai-exchange/domiciliary-account-with-bvn POST /gateway/create-domiciliary-bank-account-with-bvn Automatically create a domiciliary account using Bank Verification Number (BVN). Only supported in Nigeria. # Client End-of-Day Report Source: https://docs.fincode.technology/api/songhai-exchange/end-of-day-report POST /gateway/list-end-Of-day-position-report Get client end of day report. # Exchange Rate Source: https://docs.fincode.technology/api/songhai-exchange/exchange-rate POST /gateway/quote Get exchange rate quote. # Generate Token Source: https://docs.fincode.technology/api/songhai-exchange/generate-token POST /oauth/token Authenticate and generate an access token for API requests. # Mobile Money Creation Source: https://docs.fincode.technology/api/songhai-exchange/mobile-money-creation POST /gateway/v3/transaction/mobilemoney Create a mobile money transaction to send funds to a beneficiary's mobile wallet. Only supported in Ghana. # Mobile Money Validation Source: https://docs.fincode.technology/api/songhai-exchange/mobile-money-validation POST /gateway/account-number-validation Validate mobile money wallet number and retrieve wallet details. # Check Transaction Status Source: https://docs.fincode.technology/api/songhai-exchange/transaction-status POST /gateway/transaction/checkstatus Check the status of a transaction. # Generating Wallet Account Statement Source: https://docs.fincode.technology/api/songhai-exchange/wallet-account-statement POST /v1/services/walletmanagement/walletledgerbyclient/{startDate}/{endDate}/{currency}/ Generate wallet account statement. # Add Bank Details Source: https://docs.fincode.technology/api/transactions/add-bank-details POST /bankmanagement/add-bank-details-key-value-pairs Links a validated bank account to a beneficiary profile. After creating a beneficiary, use this endpoint to associate their bank account details. ## Request Headers The **JWT Access Token** of the authenticated user. Platform identifier. Use `fincode`. Unique request identifier. ## Request Body The unique ID of the beneficiary (returned from `new-beneficiary`). The unique ID of the customer (sender). The sender's customer code. The currency of the bank account. ISO 3166-1 alpha-3 country code. Key-value pairs of the bank details. **All keys must be lowercase exactly as listed below.** An unrecognised key causes a `400` with no response body. Must be one of the following lowercase values: | Key | Description | | - | - | | `bankname` | Bank name | | `bankaccountno` | Account number | | `accountholdername` | Account holder name | | `bankcode` | Bank code | | `swiftbic` | SWIFT / BIC code | | `sortcode` | Sort code | | `iban` | IBAN | | `branchcode` | Branch code | | `bankcity` | Bank city | | `ifsccode` | IFSC code (India) | | `mobilemoneynumber` | Mobile money number | | `bankbranchid` | Bank branch ID | | `accounttype` | Account type | | `country` | Country (ISO 3166-1 alpha-3) | Which keys are required depends on the destination country. Call `required-bank-fields/{country}` to get the exact requirements for your corridor. Field value. ## Code Example ```bash cURL theme={null} curl -X POST 'https://{your-domain}.fincode.software/api/v6/services/bankmanagement/add-bank-details-key-value-pairs' \ --header 'X-Auth-Token: YOUR_TOKEN' \ --header 'Content-Type: application/json' \ --data '{ "id": "beneficiary_uuid", "customerId": "customer_uuid", "accountOwnerCustomerCode": "RZ0LNK", "currencyCode": "NGN", "country": "NGA", "bankAccountMetaData": [ {"key": "bankname", "value": "FCMB"}, {"key": "bankaccountno", "value": "8883968718"}, {"key": "accountholdername", "value": "Ada Okonkwo"}, {"key": "bankcode", "value": "214"}, {"key": "swiftbic", "value": "FCMBNGLA"} ] }' ``` # Beneficiary Details Source: https://docs.fincode.technology/api/transactions/beneficiary-details GET /usermanagement/view-beneficiery-details/{beneficiaryId} Retrieves the full profile and banking details for a specific saved beneficiary. Retrieves all stored details for a single beneficiary, identified by the unique `{beneficiaryId}`. This includes personal information and the associated payout account details. ## Request Headers This endpoint requires a valid **Access Token** for authorization. The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint.       Platform identifier. Use `fincode`.       Unique request identifier. ## Path Parameters The unique ID of the beneficiary whose details are being requested. ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v6/services/usermanagement/view-beneficiery-details/{beneficiaryId}' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v6/services/usermanagement'; async function viewBeneficiaryDetails(accessToken, beneficiaryId) { const url = `${BASE_URL}/view-beneficiery-details/${beneficiaryId}`; try { const response = await axios.get(url, { headers: { 'X-Auth-Token': accessToken, platform: 'fincode', uuid: '200', }, }); const beneficiary = response.data; console.log( `Fetched Beneficiary: ${beneficiary.firstName} ${beneficiary.lastName}` ); console.log(`Receiving Country: ${beneficiary.countryCode}`); console.log(`Bank: ${beneficiary.bankDetails.bankName}`); console.log(`Account: ${beneficiary.bankDetails.accountNumber}`); return beneficiary; } catch (error) { console.error( 'Failed to fetch beneficiary details:', error.response?.data || error.message ); throw error; } } ``` # Find All Beneficiary Source: https://docs.fincode.technology/api/transactions/beneficiary-list GET /usermanagement/find-all-beneficiery Retrieves a list of all saved beneficiaries associated with the authenticated customer or managed by the agent. This endpoint fetches all saved recipient profiles (**beneficiaries**) linked to the authenticated user's account. This list is typically displayed when a user initiates a new transaction to select a pre-saved recipient. ## Request Headers This endpoint requires a valid **Access Token** for authorization to identify the user and their associated beneficiaries. The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint.       Platform identifier. Use `fincode`.       Unique request identifier. ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v6/services/usermanagement/find-all-beneficiery' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v6/services/usermanagement'; async function findAllBeneficiaries(accessToken) { try { const response = await axios.get(`${BASE_URL}/find-all-beneficiery`, { headers: { 'X-Auth-Token': accessToken, platform: 'fincode', uuid: '200', }, }); const beneficiaries = response.data.data; console.log(`Beneficiaries Found: ${beneficiaries.length}`); beneficiaries.forEach((b) => { console.log(`- ${b.name} (${b.country}) - Account: ${b.accountNumber}`); }); return beneficiaries; } catch (error) { console.error( 'Failed to fetch beneficiaries:', error.response?.data || error.message ); throw error; } } ``` # Get Transaction Quote Source: https://docs.fincode.technology/api/transactions/call-quote POST /quote/callQuote Calculates the real-time exchange rate, fees, and total cost for an intended transaction. Returns the live fee breakdown, exchange rate, and total send/receive amounts for a given corridor and transaction type. Call this before creating a transaction to show the customer the exact cost. The `X-Auth-Token` is optional — you can call this endpoint without a token to show rates on a public pricing page. ## Request Headers JWT Access Token. Optional for public rate lookups; include for customer-specific quotes. Platform identifier. Use `fincode`. Unique request identifier. ## Request Body The delivery method / transaction type. Common values: `ACCOUNTPAYMENT`, `MOBILE_MONEY`, `CASH_PICKUP`, `WALLET`. ISO 3166-1 alpha-3 destination country code (e.g. `NGA`). The amount the sender wants to send (in `principalAmountCurrency`). Provide either `principalAmount` or `deriveAmount`, not both. ISO 4217 currency code for `principalAmount` (e.g. `GBP`). The amount the recipient should receive (in `deriveAmountCurrency`). Use this for inverse calculation — the platform works out what the sender needs to pay. ISO 4217 currency code for `deriveAmount` (e.g. `NGN`). Set `true` when providing `deriveAmount` (recipient amount). The platform calculates the sender's cost. Default: `false`. ISO 3166-1 alpha-3 origin country code (e.g. `GBR`). Required for some pay centre configurations. Promotional code to apply a discount to fees. Mobile operator code — required when `transactionType` is `MOBILE_MONEY`. ## Code Example ```bash cURL theme={null} curl -X POST 'https://{your-domain}.fincode.software/api/v6/services/quote/callQuote' \ --header 'Content-Type: application/json' \ --header 'platform: fincode' \ --header 'uuid: 200' \ --data '{ "transactionType": "ACCOUNTPAYMENT", "destinationCountry": "NGA", "principalAmount": 100, "principalAmountCurrency": "GBP", "tradeOriginatingCountry": "GBR" }' ``` # Check Transaction Status Source: https://docs.fincode.technology/api/transactions/check-transaction-status GET /transactionmanagement/checktransactionstatus/{transaction_identification_number} Returns the current processing status of a single transaction by its PCN. Returns the current processing status of a booked transfer. Pass the PCN (Platform Control Number) returned from `create-transaction` as the path parameter. ## Request Headers JWT Access Token of the authenticated user. Platform identifier. Use `fincode`. Unique request identifier. IP address of the client making the request. ## Path Parameters The PCN of the booked transfer, as returned in the `pcn` field of the `create-transaction` response. ## Response The transaction status name (e.g. `PENDING`, `PROCESSED`, `FAILED`, `CANCELLED`). `0` when the transaction is found, `-1` when not found. Human-readable label for the current status. ## Code Examples ```bash cURL theme={null} curl -X GET 'https://{your-domain}.fincode.software/api/v6/services/transactionmanagement/checktransactionstatus/TR656516344451' \ --header 'X-Auth-Token: YOUR_TOKEN' \ --header 'platform: fincode' \ --header 'uuid: 200' \ --header 'ipAddress: 192.168.1.100' ``` ```javascript Node.js theme={null} const axios = require('axios'); const pcn = 'TR656516344451'; const response = await axios.get( `https://{your-domain}.fincode.software/api/v6/services/transactionmanagement/checktransactionstatus/${pcn}`, { headers: { 'X-Auth-Token': 'YOUR_TOKEN', 'platform': 'fincode', 'uuid': '200', 'ipAddress': '192.168.1.100' } } ); ``` # Create Beneficiary Source: https://docs.fincode.technology/api/transactions/create-beneficiary POST /usermanagement/new-beneficiary Creates a new beneficiary (recipient) profile linked to a sender. Creates a new beneficiary profile. For bank transfers, call this **after** validating the account with [Validate Recipient Account](/api/transactions/validate-account). Once created, add bank account details with [Add Bank Details](/api/transactions/add-bank-details). Requires an authenticated `REGISTERED_CUSTOMER`, `MANAGER`, or `AGENTS` token. ## Request Headers JWT Access Token of the authenticated user. Platform identifier. Use `fincode`. Unique request identifier. ## Request Body The customer code of the sender this beneficiary belongs to (e.g. `VJJGVE`). Beneficiary first name. Beneficiary last name. Beneficiary middle name. Customer type: `INDIVIDUAL` or `COMPANY`. Beneficiary email address. Beneficiary phone number. Date of birth in ISO format (e.g. `1990-05-15T00:00:00+01:00`). Company name — required when `type` is `COMPANY`. Company registration number — for `COMPANY` type. Sender's relationship to the beneficiary (e.g. `SPOUSE`, `PARENT`, `FRIEND`). Beneficiary address. Street address line 1 Street address line 2 ISO 3166-1 alpha-3 country code (e.g. `NGA`) Postcode / ZIP code Additional dynamic fields specific to your configuration. Pass an empty object `{}` if not applicable. ## Code Example ```bash cURL theme={null} curl -X POST 'https://{your-domain}.fincode.software/api/v6/services/usermanagement/new-beneficiary' \ --header 'X-Auth-Token: YOUR_TOKEN' \ --header 'Content-Type: application/json' \ --header 'platform: fincode' \ --header 'uuid: 200' \ --data '{ "senderCode": "VJJGVE", "firstName": "Ada", "lastName": "Okonkwo", "type": "INDIVIDUAL", "email": "ada.okonkwo@example.com", "phone": "+2348012345678", "dob": "1988-03-22T00:00:00+01:00", "relationShip": "FRIEND", "address": { "address1": "12 Victoria Island", "countryIso3": "NGA", "postcode": "101241" }, "dynamicFields": {} }' ``` # Create Transaction Source: https://docs.fincode.technology/api/transactions/create-transaction POST /transactionmanagement/create-transaction Initiate a new remittance transaction using existing customer profiles. Initiates a new transaction where the sender and recipient have already been onboarded. Both must have active customer profiles. ## Request Headers JWT Access Token of the authenticated user. A unique key for this transaction submission. If the same key is sent twice, the second request returns the result of the first rather than creating a duplicate transaction. Use a UUID or a unique reference from your system. IP address of the device initiating the transaction. Platform identifier. Use `fincode`. Unique request identifier. Customer's transaction password (if required by your pay centre configuration). ## Request Body The amount the recipient will receive, in the receiving currency. The amount the sender pays, in the sending currency. Whether fees are included in `sendAmount`. Set to `true` if the sender pays a fixed amount inclusive of all fees; `false` if fees are added on top. ISO 4217 currency code the sender is paying in (e.g. `GBP`). ISO 4217 currency code the recipient will receive (e.g. `NGN`). Transaction / delivery method. Common values: | Value | Description | | - | - | | `ACCOUNTPAYMENT` | Bank account transfer | | `MOBILE_MONEY` | Mobile money (e.g. M-Pesa) | | `CASH_PICKUP` | Cash pickup at agent location | | `WALLET` | Wallet transfer | Processing mode. Use `REAL_TIME` for immediate processing or `BATCH` for scheduled processing. Customer code of the sender (returned from `find-customer-by-name-or-phone-no` or `register-customer`). Customer code of the recipient/beneficiary (returned from `new-beneficiary`). Key-value pairs for the recipient's bank/account details. See the [Add Bank Details](/api/transactions/add-bank-details) key reference for the full list of valid keys. All keys must be lowercase. Field key — must be lowercase. Common values: `bankname`, `bankaccountno`, `accountholdername`, `bankcode`, `swiftbic`, `sortcode`, `iban`. Field value. Regulatory and routing information for the transfer. ISO 3166-1 alpha-3 code of the sender's country (e.g. `GBR`) ISO 3166-1 alpha-3 code of the recipient's country (e.g. `NGA`) Purpose of the transfer (e.g. `FAMILY_SUPPORT`, `GIFT`, `EDUCATION`) Declared source of funds (e.g. `SALARY`, `SAVINGS`, `BUSINESS`) Sender's relationship to the recipient (e.g. `PARENT`, `SPOUSE`, `FRIEND`) Security question for cash pickup transactions. Required when `type` is `CASH_PICKUP`. Answer to the security question. Required when `type` is `CASH_PICKUP`. Your own reference for this transaction. Optional — the platform generates one if not provided. Additional dynamic fields specific to your configuration. Pass an empty object `{}` if not applicable. List of documents attached to this transaction (for transactions requiring document verification). Pass an empty array `[]` if none. ## Code Example ```bash cURL theme={null} curl -X POST 'https://{your-domain}.fincode.software/api/v6/services/transactionmanagement/create-transaction' \ --header 'X-Auth-Token: YOUR_TOKEN' \ --header 'X-Idempotency-Key: a1b2c3d4-e5f6-7890-abcd-ef1234567890' \ --header 'ipAddress: 192.168.1.100' \ --header 'Content-Type: application/json' \ --header 'platform: fincode' \ --header 'uuid: 200' \ --data '{ "amount": 150000, "sendAmount": 100, "inclussive": false, "sendCurrency": "GBP", "receivingCurrency": "NGN", "type": "ACCOUNTPAYMENT", "transactionProcessingMode": "REAL_TIME", "preExistingSenderCustomerCode": "VJJGVE", "preExistingRecipientCustomerCode": "BNADKO", "creditParty": [ {"key": "bankname", "value": "GTBank"}, {"key": "bankaccountno", "value": "0123456789"}, {"key": "accountholdername", "value": "Ada Okonkwo"}, {"key": "bankcode", "value": "058"}, {"key": "swiftbic", "value": "GTBINGLA"} ], "internationalTransferInformation": { "originCountry": "GBR", "receivingCountry": "NGA", "remittancePurpose": "FAMILY_SUPPORT", "sourceOfFunds": "SALARY", "relationshipSender": "PARENT" }, "dynamicFields": {}, "eligibleDocumentList": [] }' ``` # Create Transaction (Direct) Source: https://docs.fincode.technology/api/transactions/create-transaction-direct POST /transactionmanagement/create-transaction Initiate a new remittance transaction using pre-registered sender and recipient customer codes. Initiates a new transaction. Both the sender and recipient must already be registered on the platform — pass their customer codes in `preExistingSenderCustomerCode` and `preExistingRecipientCustomerCode`. For the full field reference, see [Create Transaction](/api/transactions/create-transaction). ## Quick Reference | Field | Required | Notes | | - | - | - | | `X-Idempotency-Key` | Header — required | Prevents duplicate transactions on retry | | `ipAddress` | Header — required | Device IP of the person initiating the transaction | | `preExistingSenderCustomerCode` | Body — required | Sender's customer code | | `preExistingRecipientCustomerCode` | Body — required | Recipient's customer code | | `type` | Body — required | Delivery method: `ACCOUNTPAYMENT`, `MOBILE_MONEY`, `CASH_PICKUP`, `WALLET` | | `creditParty` | Body — required | Recipient account details as lowercase key-value pairs | | `internationalTransferInformation` | Body — required | `originCountry`, `receivingCountry`, `remittancePurpose`, `sourceOfFunds` | ## Code Example ```bash cURL theme={null} curl -X POST 'https://{your-domain}.fincode.software/api/v6/services/transactionmanagement/create-transaction' \ --header 'X-Auth-Token: YOUR_TOKEN' \ --header 'X-Idempotency-Key: a1b2c3d4-e5f6-7890-abcd-ef1234567890' \ --header 'ipAddress: 192.168.1.100' \ --header 'Content-Type: application/json' \ --header 'platform: fincode' \ --header 'uuid: 200' \ --data '{ "amount": 150000, "sendAmount": 100, "inclussive": false, "sendCurrency": "GBP", "receivingCurrency": "NGN", "type": "ACCOUNTPAYMENT", "transactionProcessingMode": "REAL_TIME", "preExistingSenderCustomerCode": "VJJGVE", "preExistingRecipientCustomerCode": "BNADKO", "creditParty": [ {"key": "bankname", "value": "GTBank"}, {"key": "bankaccountno", "value": "0123456789"}, {"key": "accountholdername", "value": "Ada Okonkwo"}, {"key": "bankcode", "value": "058"}, {"key": "swiftbic", "value": "GTBINGLA"} ], "internationalTransferInformation": { "originCountry": "GBR", "receivingCountry": "NGA", "remittancePurpose": "FAMILY_SUPPORT", "sourceOfFunds": "SALARY" }, "dynamicFields": {}, "eligibleDocumentList": [] }' ``` # Delivery Currencies Source: https://docs.fincode.technology/api/transactions/delivery-currencies GET /quote/supported-delivery-currencies/{sendingCountryCode}/{receivingCountryCode}/{deliveryMethod}/{sendingCurrencyCode} Retrieves the list of currencies available for the recipient to receive, given the sender's payment currency. This endpoint finalizes the currency selection by returning the payout currencies available in the destination country. It factors in the corridor and the specific **source currency** (`sendingCurrencyCode`) that the sender has chosen to pay with. ## Request Headers This endpoint requires a valid **Access Token** The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. This token must belong to a user with appropriate permissions.       Platform identifier. Use `fincode`.       Unique request identifier. ## Path Parameters The country code the customer is sending from. The country code the recipient is in. The intended payout method. The specific **source currency** the sender is paying with (e.g., `GBP`). This is the new parameter. ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v6/services/quote/supported-delivery-currencies/GBR/NGA/ACCOUNTPAYMENT/GBP' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://agent.fincode.software/api/v6/services/quote'; async function getSupportedDeliveryCurrencies( sendCountry, receiveCountry, deliveryMethod, sendCurrency ) { const url = `${BASE_URL}/supported-delivery-currencies/${sendCountry}/${receiveCountry}/${deliveryMethod}/${sendCurrency}`; try { const response = await axios.get(url, { headers: { platform: 'fincode', uuid: '200', }, }); const currencies = response.data.data; console.log( `Final Delivery Currencies available for ${sendCurrency} payment:` ); currencies.forEach((c) => { console.log( `- Receive in ${c.currencyCode} (Range: ${c.minAmount} to ${c.maxAmount})` ); }); return currencies; } catch (error) { console.error( 'Failed to fetch supported delivery currencies:', error.response?.data || error.message ); throw error; } } ``` # Destination Countries Source: https://docs.fincode.technology/api/transactions/destination-countries GET /quote/destination-country-by-delivery-method/{sendingCountryCode}/{deliveryMethod} Retrieves a list of valid destination countries for a given sending country and payout method, used for defining remittance corridors. This endpoint retrieves the list of countries where money can be sent, based on the customer's current location (`sendingCountryCode`) and the intended method of delivery (e.g., `ACCOUNTPAYMENT`). This is a key step in initiating a transaction. ## Request Headers This endpoint requires a valid **Access Token** The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. This token must belong to a user with appropriate permissions.       Platform identifier. Use `fincode`.       Unique request identifier. ## Path Parameters The dynamic parts of the URL are mandatory for filtering the results. The **country code** of the customer sending the money (ISO 3166-1 alpha-3 code). The intended **payout method** (e.g., `ACCOUNTPAYMENT`, `CASH_PICKUP`). ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v6/services/quote/destination-country-by-delivery-method/GBR/ACCOUNTPAYMENT' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://agent.fincode.software/api/v6/services/quote'; async function getDestinationCountries(sendingCountryCode, deliveryMethod) { const url = `${BASE_URL}/destination-country-by-delivery-method/${sendingCountryCode}/${deliveryMethod}`; try { const response = await axios.get(url, { headers: { platform: 'fincode', uuid: '200', }, }); const countries = response.data.data; console.log( `Available destinations from ${sendingCountryCode} via ${deliveryMethod}:` ); countries.forEach((c) => { console.log( `- ${c.countryName} (${ c.countryCode }) - Currencies: ${c.payoutCurrencies.join(', ')}` ); }); return countries; } catch (error) { console.error( 'Failed to fetch destination countries:', error.response?.data || error.message ); throw error; } } ``` # Customer Transaction History Source: https://docs.fincode.technology/api/transactions/history-data POST /transactionmanagement/history-data Retrieves a paginated and filtered list of transactions. Retrieves the transaction history with support for filtering by amount, date, currency, status, and more. Uses `POST` so the filtering parameters can be sent in the request body. ## Request Headers JWT Access Token of the authenticated user. Platform identifier. Use `fincode`. Unique request identifier. ## Request Body All fields are optional — omit any you do not need to filter by. Number of records to return (page size). Defaults to all matching records if omitted. Zero-based offset for pagination. Use with `totalNumber` to page through results. Start of the date range (ISO 8601 format, e.g. `2024-01-01T00:00:00Z`). End of the date range (ISO 8601 format, e.g. `2024-12-31T23:59:59Z`). Minimum transaction amount filter. Maximum transaction amount filter. ISO 4217 currency code to filter by (e.g. `GBP`, `NGN`). Filter by transaction status. Common values: `PENDING`, `PROCESSED`, `FAILED`, `CANCELLED`. Filter by delivery/transaction type (e.g. `ACCOUNTPAYMENT`, `MOBILE_MONEY`, `CASH_PICKUP`). ISO 3166-1 alpha-3 destination country code filter (e.g. `NGA`). Filter by transaction reference / PCN (Platform Control Number). Filter by recipient account number. Filter by recipient's customer code. Filter by sender's full name (partial match). Filter by recipient's full name (partial match). Filter by compliance check status. ## Code Example ```bash cURL theme={null} curl -X POST 'https://{your-domain}.fincode.software/api/v6/services/transactionmanagement/history-data' \ --header 'X-Auth-Token: YOUR_TOKEN' \ --header 'Content-Type: application/json' \ --header 'platform: fincode' \ --header 'uuid: 200' \ --data '{ "startNumber": 0, "totalNumber": 20, "fromDate": "2024-01-01T00:00:00Z", "toDate": "2024-12-31T23:59:59Z", "selectedCurrency": "GBP", "status": "PROCESSED" }' ``` # List Mobile Operators Source: https://docs.fincode.technology/api/transactions/list-mobile-operators GET /admin/bank/config/find-all-mobile-operator/{country} Retrieves the list of supported mobile money operators for a country. This endpoint returns the available mobile money operators (e.g., MTN, Orange, Airtel) for a specific country. The operator code is required for validating mobile numbers and creating transactions. # List Supported Banks Source: https://docs.fincode.technology/api/transactions/list-supported-banks GET /bankmanagement/list-supported-banks-iso3/{country} Retrieves the list of supported banks for a specific country. This endpoint returns a list of banks supported for payouts in the specified country. The response includes the bank code and name, which are required for validating accounts and creating transactions. ## Request Headers The **JWT Access Token** of the authenticated user. Platform identifier. Use `fincode`. Unique request identifier. ## Path Parameters ISO 3166-1 alpha-3 country code (e.g., `NGA`). ## Code Example ```bash cURL theme={null} curl -X GET 'https://{your-domain}.fincode.software/api/v6/services/bankmanagement/list-supported-banks-iso3/NGA' \ --header 'X-Auth-Token: YOUR_TOKEN' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` # Payment Methods Source: https://docs.fincode.technology/api/transactions/payment-methods POST /paymentmanagement/supported-payment-methods Retrieves available payment methods for a specific transaction context. This endpoint returns the supported payment methods (e.g., Card, Open Banking) for a given transaction context. It requires details about the sender's country, transaction amount, and currency to determine the available options and applicable fees. ```bash cURL POST theme={null} https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/supported-payment-methods ``` ## Request Headers The **JWT Access Token** of the authenticated user. Platform identifier. Use `fincode`. Unique request identifier. Must be `application/json`. ## Request Body The 3-letter ISO code of the sender's country (e.g., `GBR`). Available from the login response. The type of transaction context. Always `PAYMENT_METHOD`. The source currency code (e.g., `GBP`). The Transaction Reference Number (PCN) obtained from the create transaction step. The transaction amount. The type of payable item. Always `TRANSACTION`. The application identifier (e.g., `com.app.your_app_identifier`). ## Response Request status (e.g., `SUCCESS`). Contains the payment method metadata. List of available payment methods. The payment provider (e.g., `VOLUME`, `SECURE_TRADING`). The payment type (e.g., `ONLINE_BANK_PAYMENT`, `ONLINE_CARD_PAYMENT`). Indicates if the payment flow is hosted. Provider-specific details for the payment flow (e.g., `hosted_gateway_url`, `paymentIntentId`). The principal amount to be paid. The total amount including fees. URL to the payment terms and conditions. ## Code Examples ```bash cURL theme={null} curl -X POST 'https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/supported-payment-methods' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'platform: fincode' \ --header 'uuid: 200' \ --header 'Content-Type: application/json' \ --data '{ "countryIsoCode3": "GBR", "transactionType": "PAYMENT_METHOD", "currency": "GBP", "pcn": "TR656516344451", "amount": "2.000", "payAbleType": "TRANSACTION", "appId": "com.app.your_app_identifier" }' ``` ```javascript Node.js theme={null} const axios = require('axios'); const response = await axios.post( 'https://{your-domain}.fincode.software/api/v6/services/paymentmanagement/supported-payment-methods', { countryIsoCode3: 'GBR', transactionType: 'PAYMENT_METHOD', currency: 'GBP', pcn: 'TR656516344451', amount: '2.000', payAbleType: 'TRANSACTION', appId: 'com.app.your_app_identifier' }, { headers: { 'X-Auth-Token': 'YOUR_JWT_ACCESS_TOKEN', 'platform': 'fincode', 'uuid': '200', 'Content-Type': 'application/json' } } ); ``` # Required Bank Fields Source: https://docs.fincode.technology/api/transactions/required-bank-fields GET /bankmanagement/required-bank-fields/{country} Retrieves the specific bank fields required for a destination country. Different countries have different banking requirements (e.g., some require a Swift Code, others a Branch Code). This endpoint returns the dynamic requirements for the specified country. ## Request Headers The **JWT Access Token** of the authenticated user. Platform identifier. Use `fincode`. Unique request identifier. ## Path Parameters ISO 3166-1 alpha-3 country code (e.g., `NGA`). ## Code Example ```bash cURL theme={null} curl -X GET 'https://{your-domain}.fincode.software/api/v6/services/bankmanagement/required-bank-fields/NGA' \ --header 'X-Auth-Token: YOUR_TOKEN' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` # Supported Currencies Source: https://docs.fincode.technology/api/transactions/supported-currencies GET /quote/supported-currencies/{sendingCountryCode}/{receivingCountryCode}/{deliveryMethod} Retrieves the list of supported currencies for a specific remittance corridor and delivery method. This endpoint is the final step in determining the valid parameters for initiating a transaction. It retrieves all supported payout currencies for the specified **sending country**, **receiving country**, and **delivery method**. ## Request Headers This endpoint requires a valid **Access Token** The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint. This token must belong to a user with appropriate permissions (e.g., `MANAGER` or `AGENT`).       Platform identifier. Use `fincode`.       Unique request identifier. ## Path Parameters All path parameters are mandatory to define the specific corridor. The **country code** the customer is sending from (ISO 3166-1 alpha-3 code). The **country code** the recipient is in (ISO 3166-1 alpha-3 code). The intended **payout method** (e.g., `ACCOUNTPAYMENT`, `CASH_PICKUP`). ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v6/services/quote/supported-currencies/GBR/NGA/ACCOUNTPAYMENT' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://agent.fincode.software/api/v6/services/quote'; async function getSupportedCurrencies( sendCountry, receiveCountry, deliveryMethod ) { const url = `${BASE_URL}/supported-currencies/${sendCountry}/${receiveCountry}/${deliveryMethod}`; try { const response = await axios.get(url, { headers: { platform: 'fincode', uuid: '200', }, }); const currencies = response.data.data; console.log( `Supported Payout Currencies for ${sendCountry} to ${receiveCountry} via ${deliveryMethod}:` ); currencies.forEach((c) => { console.log( `- ${c.currencyName} (${c.currencyCode}) - Min: ${c.minAmount}, Max: ${c.maxAmount}` ); }); return currencies; } catch (error) { console.error( 'Failed to fetch supported currencies:', error.response?.data || error.message ); throw error; } } ``` # Transaction Types Source: https://docs.fincode.technology/api/transactions/transaction-types GET /transactionmanagement/transaction-types Retrieves a list of all supported transaction types available on the platform for the current organization. Retrieves a list of all currently active and supported transaction types (e.g., `ACCOUNTPAYMENT`, `CASH_PICKUP`, `BILL_PAYMENT`) available for the organization associated with the subdomain. This is typically used to populate selection menus when a user initiates a new transaction flow. ## Request Headers This endpoint is typically **open/unauthenticated** and relies on the domain to identify the tenant.       Platform identifier. Use `fincode`. Unique request identifier. ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v6/services/transactionmanagement/transaction-types' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v6/services/transactionmanagement'; async function getTransactionTypes() { try { const response = await axios.get(`${BASE_URL}/transaction-types`, { headers: { platform: 'fincode', uuid: '200', }, }); console.log('Supported Transaction Types:'); response.data.data.forEach((type) => { console.log(`- ${type.name} (${type.code}) - Module: ${type.module}`); }); return response.data.data; } catch (error) { console.error( 'Failed to fetch transaction types:', error.response?.data || error.message ); throw error; } } getTransactionTypes(); ``` # Validate Recipient Account Source: https://docs.fincode.technology/api/transactions/validate-account GET /usermanagement/validate-bank-account Validates bank account details before beneficiary creation. This endpoint validates the recipient bank account details with the destination bank or provider. It is a critical step in the Bank Transfer flow to ensure funds are sent to the correct account. ## Request Body The unique code of the bank (retrieved from `list-supported-banks`). The transaction type. Use `ACCOUNTPAYMENT` for bank transfers. The account number to validate. ISO 3166-1 alpha-3 country code of the account (e.g., `NGA`). The currency of the account (e.g., `NGN`). ## Code Example ```bash cURL theme={null} curl -X GET 'https://{your-domain}.fincode.software/api/v6/services/usermanagement/validate-bank-account' \ --header 'X-Auth-Token: YOUR_TOKEN' \ --header 'Content-Type: application/json' \ --data '{ "bankCode": "214", "transactionType": "ACCOUNTPAYMENT", "accountNumber": "8883968718", "accountNumberCountry": "NGA", "expectedCurrencyCode": "NGN" }' ``` # Wallet Account List Source: https://docs.fincode.technology/api/transactions/wallet-account GET /walletmanagement/walletaccountlist Retrieves a list of all wallet accounts associated with the authenticated user. Retrieves a list of all digital wallet accounts (e.g., currency accounts) registered under the current user's profile. This list is essential for displaying balances or selecting a source account for transactions. ## Request Headers This endpoint requires a valid **Access Token** for authorization to identify the user. The **JWT Access Token** obtained from the `/login` or `/refresh-token` endpoint.       Platform identifier. Use `fincode`.       Unique request identifier. ## Code Examples ```bash cURL theme={null} curl --location 'https://{your-domain}.fincode.software/api/v6/services/walletmanagement/walletaccountlist' \ --header 'X-Auth-Token: YOUR_JWT_ACCESS_TOKEN' \ --header 'platform: fincode' \ --header 'uuid: 200' ``` ```javascript Node.js theme={null} const axios = require('axios'); const BASE_URL = 'https://{your-domain}.fincode.software/api/v6/services/walletmanagement'; async function getWalletAccountList(accessToken) { try { const response = await axios.get(`${BASE_URL}/walletaccountlist`, { headers: { 'X-Auth-Token': accessToken, platform: 'fincode', uuid: '200', }, }); const walletAccounts = response.data.data; console.log(`Wallets Found: ${walletAccounts.length}`); walletAccounts.forEach((wallet) => { console.log( `- ${wallet.currency} Wallet: ${wallet.availableBalance} ${wallet.currency} (ID: ${wallet.walletAccountId})` ); }); return walletAccounts; } catch (error) { console.error( 'Failed to fetch wallet list:', error.response?.data || error.message ); throw error; } } ``` # Webhook Security Source: https://docs.fincode.technology/api/webhook-security Securing your webhook endpoint and handling encrypted payloads. ## Overview When receiving webhook notifications, it is important to ensure that the requests are genuinely from our system and that sensitive data is protected. This guide covers how encryption works and best practices for securing your webhook endpoint. ## Reference Encryption When encryption is enabled for your account, the `Reference` field (which contains the transaction PCN) is encrypted using your **RSA public key** before delivery. All other fields in the payload remain in plaintext. Encryption is optional and is configured on your dashboard. ### How It Works You are provided with a Base64-encoded RSA public key which is stored securely on our side and available for download on your dashboard. Before delivering each webhook event, we encrypt the `Reference` value using your public key. On receipt, you decrypt the `Reference` field using your corresponding RSA private key. ### Encrypted Payload Example When encryption is enabled, the webhook payload looks like this: ```json theme={null} { "eventType": "TRANSACTION_STATUS", "Reference": "a3F2d8x9kL2mN4pQ7rS0tU...encrypted...", "Status": "PAID", "msgNote": "Transaction completed successfully", "msgCode": "00", "transactionId": "txn-abc-123", "amountSent": 500.00, "amountReceived": 450.00, "totalAmount": 525.50, "sendingCurrencyCode": "GBP", "receivingCurrencyCode": "NGN", "beneficiaryFullName": "John Doe", "countryTo": "Nigeria" } ``` Notice that only `Reference` is encrypted. All other fields are readable. ### Unencrypted Payload Example When encryption is not enabled: ```json theme={null} { "eventType": "TRANSACTION_STATUS", "Reference": "PCN-12345", "Status": "PAID", "msgNote": "Transaction completed successfully", "msgCode": "00", "transactionId": "txn-abc-123", "amountSent": 500.00, "amountReceived": 450.00, "totalAmount": 525.50 } ``` ### Decrypting the Reference Field #### Node.js ```javascript theme={null} const crypto = require('crypto'); function decryptReference(encryptedReference, privateKeyPem) { const buffer = Buffer.from(encryptedReference, 'base64'); const decrypted = crypto.privateDecrypt( { key: privateKeyPem, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: 'sha256' }, buffer ); return decrypted.toString('utf8'); } const privateKey = fs.readFileSync('private_key.pem', 'utf8'); const decryptedPcn = decryptReference(event.Reference, privateKey); console.log('Decrypted PCN:', decryptedPcn); ``` #### Java ```java theme={null} import java.security.KeyFactory; import java.security.PrivateKey; import java.security.spec.PKCS8EncodedKeySpec; import java.util.Base64; import javax.crypto.Cipher; public class WebhookDecryptor { public static String decryptReference(String encryptedReference, String privateKeyBase64) throws Exception { byte[] keyBytes = Base64.getDecoder().decode(privateKeyBase64); PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes); PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec); Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"); cipher.init(Cipher.DECRYPT_MODE, privateKey); byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedReference)); return new String(decryptedBytes, "UTF-8"); } } ``` ### Python ```python theme={null} from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives import hashes, serialization import base64 def decrypt_reference(encrypted_reference: str, private_key_pem: str) -> str: private_key = serialization.load_pem_private_key( private_key_pem.encode(), password=None ) decrypted = private_key.decrypt( base64.b64decode(encrypted_reference), padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None ) ) return decrypted.decode('utf-8') ``` #### Securing Your Endpoint Your webhook URL **must** use HTTPS. We do not send webhook notifications to HTTP endpoints. #### IP Whitelisting For additional security, you can restrict your webhook endpoint to only accept requests from our IP addresses. Contact your account manager for the current list of IP addresses. #### Respond Quickly Return a `200` status code immediately upon receiving the webhook. Perform any heavy processing (database updates, notifications, etc.) asynchronously to avoid timeouts. ```javascript theme={null} app.post('/webhook/notify', async (req, res) => { res.status(200).json({ status: 'received' }); processWebhookAsync(req.body); }); app.post('/webhook/notify', async (req, res) => { await heavyDatabaseOperation(req.body); // might timeout await sendEmailNotification(req.body); // might timeout res.status(200).json({ status: 'received' }); }); ``` #### Idempotency The same webhook event may be delivered more than once due to retries. Always check whether you have already processed an event before acting on it. Use the `Reference` field as your deduplication key: ```javascript theme={null} const alreadyProcessed = await db.webhookEvents.findOne({ reference: event.Reference }); if (alreadyProcessed) { // Already handled — just acknowledge return res.status(200).json({ status: 'already_processed' }); } ``` ## Troubleshooting Verify that your webhook URL is correctly registered and that your server is reachable from the internet. Ensure your endpoint returns a `200` status code. This is expected behaviour during retries. Implement idempotency using the `Reference` field to avoid processing the same event twice. If encryption is enabled for your account, the `Reference` field will be Base64-encoded encrypted text. Decrypt it using your RSA private key as shown in the examples above. Ensure your server responds with exactly `200` HTTP status code. Any other code (`201`, `204`, `4xx`, `5xx`) will trigger a retry. # Webhooks Source: https://docs.fincode.technology/api/webhooks Receive real-time notifications for transaction status changes and compliance decisions. ## Overview Webhooks allow you to receive real-time HTTP notifications when key events occur on the platform. Instead of polling our API for updates, we push the data directly to your server as soon as an event occurs. We send a `POST` request to the webhook URL you registered with us, containing the full event payload. ## Webhook Events | Event | Trigger | | - | - | | `TRANSACTION_STATUS` | A payout transaction reaches a terminal status (PAID, FAILED, or CANCELLED) | | `COMPLIANCE_RISK_PROFILE_UPDATED` | A customer's compliance profile is updated following an identity verification (IDV) result or an AML screening decision | *** ## TRANSACTION\_STATUS Webhook notifications are sent for terminal transaction statuses: **PAID**, **FAILED**, and **CANCELLED**. ## How It Works Set up your webhook callback URL in the dashboard. This is the HTTPS endpoint where we will send event notifications as they occur. When a payout transaction reaches a terminal status (PAID, FAILED, or CANCELLED), we build a webhook event with the full transaction details. Each event is sent individually as a JSON payload via HTTP POST to your registered webhook URL. Your server must respond with a `200` HTTP status code to confirm receipt. Any other response code triggers a retry. ## Event Structure Each webhook notification is a JSON object with the following fields: ### Required Fields | Field | Type | Description | | - | - | - | | `eventType` | String | Type of event. Currently `TRANSACTION_STATUS`. | | `Reference` | String | Unique transaction reference (PCN). Encrypted if encryption is enabled. | | `Status` | String | Transaction status: `PAID`, `FAILED`, or `CANCELLED`. | | `msgNote` | String | Human-readable description of the event. | | `msgCode` | String | Status code from the processing provider. | ### Transaction Details | Field | Type | Description | | - | - | - | | `transactionId` | String | Internal transaction identifier. | | `amountSent` | Number | Amount sent by the sender. | | `amountReceived` | Number | Amount to be received by the beneficiary. | | `totalAmount` | Number | Total charged amount (sending amount + commission + VAT). | | `transactionDate` | String | ISO 8601 timestamp of when the transaction was created. | | `sendingCurrencyCode` | String | Currency of the sending amount (e.g., `GBP`). | | `receivingCurrencyCode` | String | Currency of the receiving amount (e.g., `NGN`). | | `bankName` | String | Destination bank name. | | `deliveryMethod` | String | How the funds are delivered (e.g., `ACCOUNTPAYMENT`, `CASHPICKUP`, `MOBILE_MONEY`). | | `beneficiaryAccountNumber` | String | Beneficiary's bank account number. | | `beneficiaryAccountHoldersName` | String | Name on the beneficiary's bank account. | | `beneficiaryFullName` | String | Full name of the beneficiary. | | `beneficiaryEmail` | String | Beneficiary's email address. | | `beneficiaryAddress` | String | Beneficiary's address. | | `sortCode` | String | Bank sort code (where applicable). | | `bankCode` | String | Bank code. | | `countryTo` | String | Destination country name. | | `transactionType` | String | Transaction type (e.g., `ACCOUNTPAYMENT`, `CASHPICKUP`). | | `paymentType` | String | Payment method used (e.g., `CARD`). | | `accountType` | String | Beneficiary account type (e.g., `SAVINGS_ACCOUNT`). | | `customer` | String | Sender's customer ID. | | `compliant` | Boolean | Whether the transaction passed compliance checks. | | `complianceCheck` | String | Compliance check result. | | `sanctionFlagColor` | String | Sanction screening flag colour. | ## Example Webhook Payload #### Successful Transaction (PAID) ```json theme={null} { "eventType": "TRANSACTION_STATUS", "Reference": "PCN-12345", "Status": "PAID", "msgNote": "Transaction completed successfully", "msgCode": "00", "transactionId": "txn-abc-123", "amountSent": 500.00, "amountReceived": 450.00, "totalAmount": 525.50, "transactionDate": "2026-02-16T18:58:55.000+00:00", "sendingCurrencyCode": "GBP", "receivingCurrencyCode": "NGN", "bankName": "Access Bank", "deliveryMethod": "ACCOUNTPAYMENT", "beneficiaryAccountNumber": "0123456789", "beneficiaryAccountHoldersName": "John Doe", "beneficiaryFullName": "John Doe", "beneficiaryEmail": "john@example.com", "beneficiaryAddress": "123 Lagos Street, Lagos", "sortCode": "123456", "bankCode": "044", "countryTo": "Nigeria", "transactionType": "ACCOUNTPAYMENT", "paymentType": "CARD", "accountType": "SAVINGS_ACCOUNT", "customer": "cust-xyz-789", "compliant": true, "complianceCheck": "PASSED", "sanctionFlagColor": "GREEN" } ``` #### Failed Transaction ```json theme={null} { "eventType": "TRANSACTION_STATUS", "Reference": "PCN-67890", "Status": "FAILED", "msgNote": "Insufficient funds", "msgCode": "0030", "transactionId": "txn-def-456", "amountSent": 1000.00, "amountReceived": 900.00, "totalAmount": 1050.00, "transactionDate": "2026-02-16T20:30:00.000+00:00", "sendingCurrencyCode": "GBP", "receivingCurrencyCode": "NGN", "bankName": "GTBank", "deliveryMethod": "ACCOUNTPAYMENT", "beneficiaryFullName": "Jane Smith", "countryTo": "Nigeria" } ``` #### Cancelled Transaction ```json theme={null} { "eventType": "TRANSACTION_STATUS", "Reference": "PCN-11111", "Status": "CANCELLED", "msgNote": "Transaction cancelled by operator", "msgCode": "00", "transactionId": "txn-ghi-789", "amountSent": 250.00, "amountReceived": 225.00, "totalAmount": 265.00, "transactionDate": "2026-02-17T10:15:00.000+00:00", "sendingCurrencyCode": "GBP", "receivingCurrencyCode": "KES", "deliveryMethod": "MOBILE_MONEY", "beneficiaryFullName": "Alex Mwangi", "countryTo": "Kenya" } ``` ### Status Values | Status | Description | | - | - | | `PAID` | Transaction successfully paid out. | | `FAILED` | Transaction failed to process. | | `CANCELLED` | Transaction was cancelled. | ### Common msgCode Values | Code | Description | Details | | - | - | - | | `00` | Success | Transaction completed. | | `0000` | Pending | Transaction is being processed. | | `0030` | Insufficient Funds | Not enough balance. | | `0031` | Invalid Account | Account not found. | | `0099` | Unknown Error | Generic processing error. | ### Retry Strategy Your server **must** respond with a `200` HTTP status code to acknowledge receipt of the webhook. If your server returns any other status code (e.g., `4xx`, `5xx`) or the request times out, the webhook delivery is considered failed and **will be retried**. If your endpoint consistently fails, the message will be retried until the SQS message retention period expires. Ensure your endpoint is reliable and responds promptly. ### Handling Webhooks Return a `200` status code as fast as possible. Do any heavy processing asynchronously after acknowledging the webhook. The same event may be delivered more than once. Use the `Reference` field to deduplicate and avoid processing the same transaction twice. See [Webhook Security](/api/webhook-security) for how to verify that requests are genuinely from our system. Your endpoint should handle `PAID`, `FAILED`, and `CANCELLED` statuses gracefully. #### Example Implementation (Node.js) ```javascript theme={null} app.post('/webhook/notify', async (req, res) => { const event = req.body; if (!event.eventType || !event.Reference || !event.Status) { return res.status(400).json({ error: 'Missing required fields' }); } const alreadyProcessed = await db.webhookEvents.findOne({ reference: event.Reference }); if (alreadyProcessed) { return res.status(200).json({ status: 'already_processed' }); } res.status(200).json({ status: 'received' }); try { switch (event.Status) { case 'PAID': await markTransactionAsPaid(event); break; case 'FAILED': await markTransactionAsFailed(event); break; case 'CANCELLED': await markTransactionAsCancelled(event); break; } // store to prevent duplicate processing await db.webhookEvents.insert({ reference: event.Reference, eventType: event.eventType, status: event.Status, processedAt: new Date(), payload: event }); } catch (error) { console.error('Error processing webhook:', error); } }); ``` #### Example Implementation (Java / Spring Boot) ```java theme={null} @RestController @RequestMapping("/webhook") public class WebhookController { @PostMapping("/notify") public ResponseEntity> handleWebhook(@RequestBody Map event) { String reference = (String) event.get("Reference"); String status = (String) event.get("Status"); String eventType = (String) event.get("eventType"); if (reference == null || status == null || eventType == null) { return ResponseEntity.badRequest() .body(Map.of("error", "Missing required fields")); } if (webhookEventRepository.existsByReference(reference)) { return ResponseEntity.ok(Map.of("status", "already_processed")); } switch (status) { case "PAID": transactionService.markAsPaid(reference, event); break; case "FAILED": transactionService.markAsFailed(reference, event); break; case "CANCELLED": transactionService.markAsCancelled(reference, event); break; } webhookEventRepository.save(new WebhookEvent(reference, eventType, status)); return ResponseEntity.ok(Map.of("status", "received")); } } ``` *** ## COMPLIANCE\_RISK\_PROFILE\_UPDATED This event is fired whenever a customer's compliance risk profile is updated. It is triggered by two situations: * **Identity verification (IDV) result** — when an eKYC provider returns a decision and our system processes it. * **AML screening update** — when a sanctions, PEP, or adverse media screening produces a new result. Use this event to keep your own customer records in sync with our compliance decisions without polling. ### Payload Fields | Field | Type | Description | | - | - | - | | `eventType` | String | Always `COMPLIANCE_RISK_PROFILE_UPDATED` | | `userId` | String | Unique identifier of the customer | | `firstName` | String | Customer's first name | | `lastName` | String | Customer's last name | | `email` | String | Customer's email address | | `phone` | String | Customer's phone number | | `complianceDecision` | String | Current compliance decision: `APPROVED`, `UNDER_REVIEW`, or `REJECTED` | | `riskLevel` | String | Current risk level: `LOW`, `MEDIUM`, or `HIGH` | | `currentRiskScore` | Number | Current proven risk score | | `maximumPotentialRiskScore` | Number | Maximum possible risk score based on the active configuration | | `currentRiskScoreRatio` | Number | Ratio of current risk to maximum potential risk (0 to 1) | | `currentTrustScore` | Number | Accumulated trust score from passed checks | | `relativeMaximumRisk` | Number | Remaining unknown risk (negative means fully proven) | | `sanctionsMatch` | Boolean | `true` if the customer matched a sanctions list entry | | `pepMatch` | Boolean | `true` if the customer was identified as a Politically Exposed Person | | `adverseMediaMatch` | Boolean | `true` if adverse media results were found | | `adverseMediaCount` | Number | Number of adverse media hits | | `documentVerificationStatus` | String | Status of document verification: `VERIFIED`, `PENDING`, `FAILED` | | `fullNameMatch` | Boolean | `true` if the name on the document fully matched the registered name | | `partialNameMatch` | Boolean | `true` if the name was a partial match | | `nameMatchPercentage` | Number | Percentage similarity between the document name and the registered name | | `didNotMatchSignUpName` | Boolean | `true` if the document name did not match the sign-up name | | `sourceOfFundsVerified` | Boolean | `true` if source of funds has been verified | | `status` | String | Current customer account status | | `kycLastUpdateDate` | String | ISO 8601 timestamp of the last KYC update | | `defaultIdentificationDocument` | Object | Most recently verified identity document (see below) | | `complianceApprovalHistories` | Array | Ordered list of all compliance scoring events (see below) | | `customerKycVerificationRecordEntity` | Array | List of all KYC requirements and their current completion state (see below) | #### defaultIdentificationDocument | Field | Type | Description | | - | - | - | | `documentNumber` | String | The document's reference number | | `identificationType` | String | Document type, e.g. `PASSPORT`, `DRIVING_LICENSE`, `NATIONAL_ID_CARD` | #### complianceApprovalHistories Each entry represents one compliance scoring event, in chronological order. | Field | Type | Description | | - | - | - | | `checkCategory` | String | The check that produced this entry, e.g. `Sanctions`, `PEP (Politically Exposed Person)`, `Face Match`, `KYC Rule: 04` | | `scoreType` | String | Whether this entry added to risk or trust: `RISK` or `TRUST` | | `complianceScore` | Number | Points applied. Negative = risk added; positive = trust earned | | `complianceStatus` | String | Outcome of this check: `APPROVED`, `UNDER_REVIEW`, `PENDING_VERIFICATION` | | `riskLevel` | String | Risk level at the time of this entry | | `reason` | String | Human-readable description of why this entry was created | | `createdDate` | String | ISO 8601 timestamp of when this entry was created | | `updatedDate` | String | ISO 8601 timestamp of when this entry was last updated | #### customerKycVerificationRecordEntity Each entry represents one KYC requirement assigned to the customer. | Field | Type | Description | | - | - | - | | `id` | String | The KYC record ID — this is the `associatedRuleId` to pass when uploading documents | | `actionType` | String | Type of requirement, e.g. `VERIFY_ACCOUNT_VIA_EKYC`, `ADDRESS_PROOF`, `VERIFY_ACCOUNT_VIA_PHONE_NUMBER` | | `idType` | String | Document type required, if applicable (e.g. `ADDRESS_PROOF`) | | `complianceDecision` | String | Compliance decision for this specific rule: `APPROVED`, `UNDER_REVIEW`, `REJECTED` | | `restriction` | String | Action taken if this rule is outstanding: `BLOCK` | | `executed` | Boolean | `true` if this requirement has been completed | | `expired` | Boolean | `true` if this requirement has expired | | `executionDate` | String | ISO 8601 timestamp of when the requirement was completed | | `creationDate` | String | ISO 8601 timestamp of when the requirement was assigned | | `ruleExpiredDate` | String | ISO 8601 timestamp of when this rule expired, if applicable | | `idRequired` | Boolean | `true` if an identity document is required for this rule | | `idRequiredCompleted` | Boolean | `true` if the identity document requirement has been fulfilled | | `addressProofRequired` | Boolean | `true` if proof of address is required for this rule | | `addressProofRequiredCompleted` | Boolean | `true` if the proof of address requirement has been fulfilled | | `sourceOfIncomeRequired` | Boolean | `true` if proof of source of income is required for this rule | | `sourceOfIncomeRequiredCompleted` | Boolean | `true` if the source of income requirement has been fulfilled | ### complianceDecision Values | Value | Meaning | | - | - | | `APPROVED` | Customer has passed all required checks and is cleared to transact | | `UNDER_REVIEW` | One or more checks returned a partial or uncertain result — manual review is pending | | `REJECTED` | Customer has failed one or more checks and is blocked from transacting | ### Example Payload ```json theme={null} { "eventType": "COMPLIANCE_RISK_PROFILE_UPDATED", "userId": "00000000-0000-0000-0000-000000000001", "firstName": "John", "lastName": "Smith", "email": "john.smith@example.com", "phone": "447000000000", "complianceDecision": "UNDER_REVIEW", "riskLevel": "HIGH", "currentRiskScore": 18, "maximumPotentialRiskScore": 154, "currentRiskScoreRatio": 0.12, "currentTrustScore": 170, "relativeMaximumRisk": -16, "sanctionsMatch": false, "pepMatch": false, "adverseMediaMatch": false, "adverseMediaCount": 0, "documentVerificationStatus": "VERIFIED", "fullNameMatch": true, "partialNameMatch": false, "nameMatchPercentage": 85.0, "didNotMatchSignUpName": false, "sourceOfFundsVerified": false, "status": "PENDING", "kycLastUpdateDate": "2026-01-15T10:30:00.000+00:00", "defaultIdentificationDocument": { "documentNumber": "AB123456", "identificationType": "PASSPORT" }, "complianceApprovalHistories": [ { "checkCategory": "Sanctions", "scoreType": "TRUST", "complianceScore": 25, "complianceStatus": "APPROVED", "riskLevel": "HIGH", "reason": "Sanctions", "createdDate": "2026-01-15T10:30:00.000+00:00" }, { "checkCategory": "PEP (Politically Exposed Person)", "scoreType": "TRUST", "complianceScore": 20, "complianceStatus": "APPROVED", "riskLevel": "HIGH", "reason": "PEP (Politically Exposed Person)", "createdDate": "2026-01-15T10:30:00.000+00:00" }, { "checkCategory": "KYC Rule: 04", "scoreType": "RISK", "complianceScore": -10, "complianceStatus": "UNDER_REVIEW", "riskLevel": "HIGH", "reason": "New KYC Rule added: 04", "createdDate": "2026-01-15T09:00:00.000+00:00" } ], "customerKycVerificationRecordEntity": [ { "id": "00000000-0000-0000-0000-000000000001", "actionType": "VERIFY_ACCOUNT_VIA_EKYC", "restriction": "BLOCK", "executed": true, "expired": false, "executionDate": "2026-01-15T10:30:00.000+00:00", "creationDate": "2026-01-15T09:00:00.000+00:00" }, { "id": "00000000-0000-0000-0000-000000000002", "actionType": "ADDRESS_PROOF", "idType": "ADDRESS_PROOF", "restriction": "BLOCK", "executed": false, "expired": false, "creationDate": "2026-01-15T09:00:00.000+00:00" }, { "id": "00000000-0000-0000-0000-000000000003", "actionType": "VERIFY_ACCOUNT_VIA_PHONE_NUMBER", "restriction": "BLOCK", "executed": false, "expired": false, "creationDate": "2026-01-15T09:00:00.000+00:00" } ] } ``` # Authentication Source: https://docs.fincode.technology/authentication Secure authentication and role-based access control for the FinCode platform. FinCode uses a role-based authentication system with JWT tokens to secure API access. Each user is assigned a specific role that determines their permissions and accessible resources within your tenant. All API requests must include a valid access token in the Authorization header otherwise stated. ## Authentication Flow ```mermaid theme={null} sequenceDiagram participant Client participant API participant Auth Service participant Database Client->>API: PUT /auth/login (credentials) API->>Auth Service: Validate credentials Auth Service->>Database: Check user & role Database-->>Auth Service: User data Auth Service-->>API: Generate JWT tokens API-->>Client: Access token + Refresh token Client->>API: API Request + Auth token API->>Auth Service: Validate token Auth Service-->>API: Token valid + permissions API-->>Client: Response ``` ## User Roles & Permissions * Plugins management * Agent configuration * KYC/AML configuration * Analytics and reporting * Process transaction refunds. * Organisation user management * Crossboarder setup & operations * Call-over reports * Corridor management * View customer profiles * Transaction status updates * Exchange rate and fee markups * Tenant-specific analytics and reporting * Print receipts * Process payments * Create transactions * Handle cash collections * View transaction history * Verify transaction details * Request quotes * Initiate transfers * Create beneficiaries * View own transactions * View transaction history * Update profile information ## Server-to-Server Authentication FinCode supports server-to-server authentication using JWT tokens, allowing your systems to interact programmatically with the API. This ensures secure, stateless communication for backend integrations. For comprehensive details on securing your integration, including best practices for managing credentials, please refer to the [Security](/overview/security) section. ## API Token Authentication For backend services and integrations that require simpler, long-lived authentication, FinCode provides **API Tokens**. These tokens are generated from your dashboard and allow you to call authenticated endpoints without going through the login flow. API Tokens are ideal for server-to-server communication, scheduled jobs, and automated processes where the standard login flow is impractical. ### Key Features * **Custom Expiry**: Choose from 24 hours, 1 month, 3 months, 6 months, or 1 year * **Multiple Tokens**: Create separate tokens for different services or environments * **Full Control**: Rotate, invalidate, or delete tokens anytime from your dashboard ### Using API Tokens Include the token in the `X-Auth-Token` header: ```bash theme={null} curl -X GET "https://{domain}.fincode.software/api/v6/services/your-endpoint" \ -H "Content-Type: application/json" \ -H "X-Auth-Token: your-api-token-here" \ -H "platform: fincode" \ -H "uuid: 200" ``` For complete details on API tokens, encryption keys, and when to use each, see the Encryption Keys and Tokens guide. ## Interactive Authentication Testing Test authentication for different user roles in your sandbox environment. Select a role to see the appropriate login request and response. ### Manager Authentication Managers have full access to all platform features and administrative functions. **Login Request:** ```bash theme={null} curl -X PUT "https://{domain}.fincode.software/api/v6/services/securitymanagement/login" \ -H "Content-Type: application/json" \ -H "platform: fincode" \ -H "uuid: 200" \ -d '{ "email": "manager@yourcompany.com", "currentPassword": "your-secure-password" }' ``` **Node.js Example:** ```javascript theme={null} const axios = require('axios'); async function loginAsManager() { const response = await axios.put( 'https://{domain}.fincode.software/api/v6/services/securitymanagement/login', { email: 'manager@yourcompany.com', currentPassword: 'your-secure-password' }, { headers: { 'Content-Type': 'application/json', 'platform': "fincode", 'uuid': "200", } } ); return response.data; } ``` **Expected Response:** ```json theme={null} { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expires_in": 3600, "refresh_token": "def50200a1b2c3d4e5f6...", "user": { "id": "user_mgr_123", "email": "manager@yourcompany.com", "role": "MANAGER", "tenant_id": "tenant_456", "permissions": [ "users:read", "users:write", "transactions:read", "transactions:write", "reports:read", "settings:write", "webhooks:manage" ] } } ``` ### Agent Authentication Agents handle customer-facing operations and transaction processing. **Login Request:** ```bash theme={null} curl -X PUT "https://{domain}.fincode.software/api/v6/services/securitymanagement/login" \ -H "Content-Type: application/json" \ -H "platform: fincode" \ -H "uuid: 200" \ -d '{ "email": "agent@yourcompany.com", "currentPassword": "your-secure-password" }' ``` **Node.js Example:** ```javascript theme={null} const axios = require('axios'); async function loginAsAgent() { const response = await axios.put( 'https://{domain}.fincode.software/api/v6/services/securitymanagement/login', { email: 'agent@yourcompany.com', currentPassword: 'your-secure-password' }, { headers: { 'Content-Type': 'application/json', 'platform': 'fincode', 'uuid': '200' } } ); return response.data; } ``` **Expected Response:** ```json theme={null} { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expires_in": 3600, "refresh_token": "def50200a1b2c3d4e5f6...", "user": { "id": "user_agt_456", "email": "agent@yourcompany.com", "role": "AGENT", "tenant_id": "tenant_456", "permissions": [ "transactions:read", "transactions:create", "transactions:update", "customers:read", "customers:verify", "kyc:perform", "reports:read" ] } } ``` ### Cashier Authentication Cashiers handle payment processing and cash transactions at physical locations. **Login Request:** ```bash theme={null} curl -X PUT "https://{domain}.fincode.software/api/v6/services/securitymanagement/login" \ -H "Content-Type: application/json" \ -H "platform: fincode" \ -H "uuid: 200" \ -d '{ "email": "cashier@yourcompany.com", "currentPassword": "your-secure-password" }' ``` **Node.js Example:** ```javascript theme={null} const axios = require('axios'); async function loginAsCashier() { const response = await axios.put( 'https://{domain}.fincode.software/api/v6/services/securitymanagement/login', { email: 'cashier@yourcompany.com', currentPassword: 'your-secure-password' }, { headers: { 'Content-Type': 'application/json', 'platform': 'fincode', 'uuid': '200', } } ); return response.data; } ``` **Expected Response:** ```json theme={null} { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expires_in": 3600, "refresh_token": "def50200a1b2c3d4e5f6...", "user": { "id": "user_csh_789", "email": "cashier@yourcompany.com", "role": "CASHIER", "tenant_id": "tenant_456", "permissions": [ "transactions:create", "transactions:read", "payments:process", "cash:handle", "receipts:print" ] } } ``` ### Customer Authentication Registered customers can access self-service features through your customer portal. **Login Request:** ```bash theme={null} curl -X PUT "https://{domain}.fincode.software/api/v6/services/securitymanagement/login" \ -H "Content-Type: application/json" \ -H "platform: fincode" \ -H "uuid: 200" \ -d '{ "email": "customer@example.com", "currentPassword": "customer-password" }' ``` **Node.js Example:** ```javascript theme={null} const axios = require('axios'); async function loginAsCustomer() { const response = await axios.put( 'https://{domain}.fincode.software/sandbox/api/v6/services/securitymanagement/login', { email: 'customer@example.com', currentPassword: 'customer-password' }, { headers: { 'Content-Type': 'application/json', 'platform': 'fincode', 'uuid': '200', } } ); return response.data; } ``` **Expected Response:** ```json theme={null} { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expires_in": 3600, "refresh_token": "def50200a1b2c3d4e5f6...", "user": { "id": "user_cust_101", "email": "customer@example.com", "role": "CUSTOMER", "tenant_id": "tenant_456", "customer_id": "cust_202", "permissions": [ "profile:read", "profile:update", "transactions:create", "transactions:read:own", "beneficiaries:manage", "quotes:request" ] } } ``` ## Making Authenticated Requests Once authenticated, include the access token in all subsequent API requests: ```javascript theme={null} const axios = require('axios'); const response = await axios.get( 'https://{domain}.fincode.software/api/v6/services/admin/organisation-preference-management/fetch-organisaction-preference', { headers: { 'X-Auth-Token': process.env.JWT_ACCESS_TOKEN, 'Content-Type': 'application/json', platform: 'fincode', uuid: '200', }, } ); ``` **Required Headers:** * `Authorization: Bearer {access_token}` - Your JWT access token * `X-Auth-Token: {api_token}` - Your JWT access token * `Content-Type: application/json` - For POST/PUT requests * `platform: fincode` - For identifying request platform * `uuid: 200` - Unique uuid string ## Token Management ### Token Expiration Access tokens expire after **1 hour**. You have two options to maintain authentication: Use the refresh token to obtain a new access token without re-authentication: ```javascript theme={null} async function refreshAccessToken(refreshToken) { const response = await axios.post( 'https://{domain}.fincode.software/api/v6/services/securitymanagement/refresh', { refresh_token: refreshToken }, { headers: { 'Content-Type': 'application/json', 'X-Auth-Token': process.env.JWT_ACCESS_TOKEN, 'platform': 'fincode', 'uuid': '200', } } ); return response.data; } ``` **Response:** ```json theme={null} { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expires_in": 3600 } ``` Implement automatic token refresh in your application: ```javascript theme={null} let accessToken = null; let refreshToken = null; let tokenExpiry = null; async function ensureValidToken() { if (!tokenExpiry || Date.now() >= tokenExpiry - 300000) { if (refreshToken) { const data = await refreshAccessToken(refreshToken); accessToken = data.access_token; tokenExpiry = Date.now() + (data.expires_in * 1000); } else { const data = await login(); accessToken = data.access_token; refreshToken = data.refresh_token; tokenExpiry = Date.now() + (data.expires_in * 1000); } } return accessToken; } const token = await ensureValidToken(); ``` ### Token Revocation Revoke tokens when logging out or if compromised: ```javascript theme={null} async function logout(accessToken) { await axios.post( 'https://{domain}.fincode.software/api/v6/services/securitymanagement/logout', {}, { headers: { 'X-Auth-Token': process.env.JWT_ACCESS_TOKEN, platform: 'fincode', uuid: '200', }, } ); } ``` ## Security Best Practices * Store tokens in secure, httpOnly cookies for web apps * Use secure storage mechanisms on mobile (Keychain/KeyStore) * Never store tokens in localStorage or sessionStorage * Encrypt tokens at rest in your backend * Rotate refresh tokens after each use - Implement token expiration monitoring * Set up automatic token refresh - Handle token refresh failures gracefully * Always use HTTPS in production * Implement certificate pinning for apps * Use secure communication channels * Monitor for man-in-the-middle attacks * Follow principle of least privilege * Regularly audit user permissions * Implement session timeout * Log all authentication attempts ## Role Permission Matrix | Permission | MANAGER | AGENT | CASHIER | CUSTOMER | | - | - | - | - | - | | Create Transactions | ❌ | ❌ | ✅ | ✅ (own) | | View All Transactions | ✅ | ✅ | ❌ | ❌ | | Update Transactions | ✅ | ✅ | ✅ | ❌ | | Manage Users | ✅ | ✅ (own) | ✅ | ❌ | | KYC/AML Configuration | ✅ | ❌ | ❌ | ❌ | | KYC/AML Verification | ❌ | ❌ | ❌ | ✅ | | Tenant Configuration | ✅ | ❌ | ❌ | ❌ | | Process Refunds | ✅ | ❌ | ❌ | ❌ | | Analytics/Reports | ✅ | ✅ (limited) | ❌ | ❌ | | Manage Beneficiaries | ✅ | ❌ | ❌ | ✅ (own) | | Plugin Management | ✅ | ❌ | ❌ | ❌ | | Agent Configuration | ✅ | ❌ | ❌ | ❌ | | Rate/Fee Markups | ❌ | ❌ | ❌ | ✅ (own) | | Request quotes | ❌ | ❌ | ✅ | ✅ | ## Error Handling **Causes:** * Invalid or expired access token * Missing Authorization header * Malformed JWT token **Solution:** ```javascript theme={null} axios.interceptors.response.use( response => response, async error => { if (error.response?.status === 401) { try { const newToken = await refreshAccessToken(refreshToken); error.config.headers['Authorization'] = `Bearer ${newToken.access_token}`; return axios.request(error.config); } catch (refreshError) { window.location.href = '/login'; } } return Promise.reject(error); } ); ``` **Causes:** * Insufficient permissions for the requested resource * Role doesn't have access to the endpoint * Attempting to access another user's data **Response:** ```json theme={null} { "error": "forbidden", "message": "Insufficient permissions to access this resource", "role": "CASHIER" } ``` ## Next Steps Learn about payload encryption and API token authentication Set up real-time notifications for authentication events Deep dive into FinCode's security architecture Complete your integration and go live! # Overview Source: https://docs.fincode.technology/ciam/overview Welcome to the **Customer Identity & Access Management (CIAM)** documentation. This guide will help you understand the core infrastructure capabilities of the FinCode platform, including user management, compliance, security, and connector configurations. ### What is CIAM? The CIAM is the **central nervous system** of the FinCode platform. It manages the fundamental entities and rules that govern system behavior. The engine handles: * **User Management** - Customer identity, profiles, and authentication * **Compliance & KYC** - AML rules, KYC requirements, and document verification * **Security & Access** - PIN management, password policies, and OTP verification * **System Configuration** - Connectors, organization preferences, and fees ### Key Features Manage customer and employee profiles, roles, and access rights across the platform. Configure AML rules and KYC requirements specific to countries, transaction types, and risk levels. Robust security features including transaction PINs, login OTPs, and strict password policies. Manage 3rd-party integrations and connector instances for payments and services. Set global preferences, fee structures, and branching logic for your organization. Securely upload, attach, and verify required customer documents for compliance. ### Core Domains The CIAM is divided into several key functional areas: #### 1. User Management Centralized management of all user types within the system. * **Customer Profiles**: Create, verify, and update customer details. * **Employee Management**: Manage staff access, roles, and permissions. * **Status Control**: Activate or deactivate user accounts instantly. Explore user management endpoints. #### 2. Compliance & KYC A flexible compliance engine that adapts to regulatory requirements. * **AML Rules**: Define blocks and warnings based on transaction amounts, velocity, and patterns. * **KYC Tiers**: Configure document requirements based on customer triggers. * **Dynamic Fields**: handle custom compliance data fields for different regions. Explore compliance and AML endpoints. #### 3. Security Fundamentals Essential security tools to protect user accounts and transactions. * **PIN Management**: Issue and reset transaction and user PINs. * **OTP Verification**: Secure 2-factor authentication workflows. * **Password Policies**: Enforce organizational security standards. Explore security management tools. #### 4. Infrastructure & Config Tools for configuring the platform's operational backbone. * **Connectors**: Manage API connections to external payment and service providers. * **Branches & Pay Points**: Configure physical and digital payout locations. * **Fees & Charges**: Set default charges and fee structures. ### Integration Quick Start To start building with the CIAM: Obtain your `X-Auth-Token` via the [Login API](/api/auth/login). Use the [Compliance APIs](/api/ciam/kyc-requirements-by-isocountry) to checks mandatory fields for your target region. Create customers using the [Create Customer API](/api/ciam/create-customer). Upload documents and run verification checks. ### Next Steps Start onboarding and managing users. Configure your compliance framework. Review security policies and PIN management. Manage organization-wide settings. # Bank Transfers Source: https://docs.fincode.technology/deposit-engine/bank-transfers Bank transfers allow customers to pay offline and notify the system when payment is made. Admin approval is required to complete the transaction. ## Bank Transfer Flow ```mermaid theme={null} flowchart TD A[PENDING_PAYMENT] --> B[AWAITING_APPROVAL] B --> C[PAID] B --> D[CANCELLED] C --> E[PAID_OUT] C --> F[CANCELLED] ``` ### Key Features * **Offline Payment**: Customer transfers money via their bank. * **Admin Verification**: Payment requires confirmation by system admin. * **Notifications**: Alerts sent to admin and customer when payment is made. * **Flexible Timing**: Customer can pay later using `bank_pay_later` option. ### API Endpoints * **Notify Bank Transfer Payment** ```http theme={null} POST /notify-bank-transfer-payment ``` * **Mark I Will Pay Later** ```http theme={null} PUT /bank-iwillpaylater-wallet/{pcn}/{payableType} ``` ### Best Practices * Use `AWAITING_APPROVAL` to track payments waiting for verification. * Admin should verify bank transfer before marking as `PAID`. * Ensure notifications are triggered for both customer and admin. * Handle `CANCELLED` state if payment is not received. Learn how to notify and confirm bank transfer payments. ``` ``` # Card Payments Source: https://docs.fincode.technology/deposit-engine/card-payments Card payments allow customers to pay using debit or credit cards through integrated payment gateways. Payment may succeed or fail based on gateway verification. ## Card Payment Flow ```mermaid theme={null} flowchart TD A[PENDING_PAYMENT] --> B[CONFIRMED] B --> C[PAID] B --> D[FAILED] C --> E[PAID_OUT] ``` ### Key Features * **Secure Payment Gateway**: Process payments using PCI-compliant gateways. * **Instant Verification**: Payment status confirmed immediately by gateway. * **Error Handling**: Manage declined transactions with proper feedback. * **Multi-Currency Support**: Process payments in supported currencies. ### API Endpoint * **Process Card Payment** ```http theme={null} POST /process-card-payment ``` ### Request Example ```json theme={null} { "currencyiso3a": "USD", "pan": "4111111111111111", "expirydate": "12/2026", "securitycode": "123", "requesttypedescriptions": "wallet funding", "baseamount": "100.00", "pcn": "PCN123456" } ``` ### Best Practices * Validate card details before sending to gateway. * Handle `FAILED` transactions with retries or alternative payment methods. * Log transaction reference for reconciliation and auditing. * Implement webhooks or polling to monitor payment status. Learn how to process card payments via API. ``` ``` # Overview Source: https://docs.fincode.technology/deposit-engine/overview Welcome to the deposit platform documentation. This guide will help you understand how our digital payment system works and how to integrate it into your application. ### What is Deposit Management? Our deposit platform enables **secure, flexible, and automated payment processing** for customers. The system supports: * **Multiple Payment Methods** - Wallet, bank transfer, card payments, and more * **Automated Payment Processing** - Real-time payment verification and confirmation * **Payment Tracking** - Comprehensive payment history and status monitoring * **Flexible Payment Options** - Support for various payment gateways and methods ### Key Features Accept payments via wallet, bank transfer, card, PayPal, mobile money, and cryptocurrency. Instant payment verification with automated status updates and notifications. Track and manage payments that customers commit to making later via bank transfer. Seamless integration with multiple payment gateways including Flutterwave, Stripe, and more. Built-in wallet system for instant payments with balance management. RESTful APIs with comprehensive documentation for seamless integration. ### How It Works The payment flow consists of four main phases: Customer selects their preferred payment method from available options based on currency and amount. System creates a payable item and processes payment through the selected method (wallet, card, bank transfer). Payment is processed via the appropriate gateway or internal system with real-time status updates. System confirms payment receipt and updates transaction status, completing the payment lifecycle. For detailed visual flow, see the [Process Flow](/deposit-engine/process-flows) and [Payment Lifecycle](/deposit-engine/payment-lifecycle) pages. ### Core Concepts #### Payment Lifecycle Every payment moves through defined states from initiation to completion: ``` PENDING_PAYMENT → CONFIRMED → PAID → COMPLETED ``` Payments can also transition to `CANCELLED`, `FAILED`, or `REFUNDED` at various stages. See detailed state transitions and what triggers each status change. #### Payable Items Payable items represent different types of transactions that can be paid for: * **TRANSACTION** - Remittance/money transfer * **WALLET** - Wallet funding or generic wallet payment * **BILL** - Bill payment * **MERCHANT** - Product/merchant payment * **VOUCHER** - Voucher purchase * **WITHDRAWAL** - Wallet withdrawal Understand how different payable types are processed. #### Payment Methods The platform supports multiple payment methods: * **E\_WALLET** - Pay from customer wallet balance * **ONLINE\_CARD\_PAYMENT** - Credit/debit card payments via payment gateway * **BANK\_TRANSFER** - Offline bank transfer with confirmation * **ONLINE\_BANK\_TRANSFER** - Direct online bank transfer * **PAYPAL** - PayPal payments * **MOBILE\_MONEY** - Mobile money payments * **CRYPTO\_CURRENCY\_PAYMENT** - Cryptocurrency payments * **CASH** - Cash payments at branches Explore payment methods in detail. #### Awaiting Payments The "awaiting payments" system allows customers to notify the platform that they will pay via bank transfer: * Customer initiates transaction * Selects "I will pay later" option * Makes bank transfer offline * Notifies system of payment completion * Admin verifies and confirms payment Understand the bank transfer workflow. ### Integration Quick Start Before you begin: Contact our team to receive your sandbox API keys and base URL. Familiarize yourself with our [Payment API Reference](/api/deposit-engine/supported-payment-methods). Read through the [Payment Flow](/deposit-engine/process-flow) to understand the complete payment journey. Explore all available payment endpoints with request/response examples. ### Payment Process #### 1. Get Supported Payment Methods First, retrieve available payment methods for the transaction: ``` POST /supported-payment-methods ``` This returns available payment methods with their charges, fees, and metadata. #### 2. Customer Selects Payment Method Customer reviews options and selects their preferred payment method. #### 3. Process Payment Depending on the selected method: **Wallet Payment:** ``` POST /makepaymentfromwalletaccount ``` **Card Payment:** ``` POST /process-card-payment ``` **Bank Transfer:** ``` PUT /bank-iwillpaylater-wallet/{pcn}/{payableType} ``` #### 4. Track Payment Status Monitor payment status through: ``` GET /awaiting-payments ``` Detailed step-by-step payment processing flow. ### Supported Features #### Multi-Currency Support * Process payments in multiple currencies * Automatic currency conversion where applicable * Currency-specific payment method availability #### Payment Gateway Integration * Flutterwave (Rave) * Stripe * SecureTrading * PayPal * Custom payment gateways #### Charge Calculation * Automatic fee calculation based on payment method * Tax calculation * Payment method fees * Currency conversion fees View payment method charges. ### Testing & Sandbox We provide a full-featured sandbox environment for testing: * **Sandbox URL**: `https://{domain}.fincode.software` * **Test credentials**: Provided upon registration * **Mock payment gateways**: Simulate payment processing * **No real money**: All transactions are simulated Use the sandbox to test all payment flows, edge cases, and error handling before going live. ### Integration Models We support flexible integration approaches: ### End-to-End Integration Build the complete payment experience within your application, managing the entire customer journey from payment initiation to confirmation. **Flow**: 1. Create payable item 2. Fetch supported payment methods 3. Customer selects payment method 4. Process payment 5. Confirm payment 6. Complete transaction **Documentation**: * [Complete Payment Flow](/deposit-engine/process-flow) * [Supported Payment Methods API](/api/deposit-engine/supported-payment-methods) * [Authentication](/api/authentication) ### Direct API Integration If you manage your own payment interface, you can integrate our payment APIs directly into your system. **Flow**: ``` Your System (Payment Interface) ↓ Submit Payment Request (via API) ↓ Our System (Payment Processing) ↓ Your System (Receive Status Updates) ↓ Payment Completed / Failed ``` **What You Handle**: * Payment interface and experience * Payment method selection UI * Status display and notifications **What We Handle**: * Payment gateway integration * Payment processing * Payment verification * Transaction tracking All payment operations are accessible via our REST APIs. See the [API Reference](/api/deposit-engine/supported-payment-methods) for details. ## Next Steps Visualize the complete payment journey with detailed diagrams Understand payment states and transitions from initiation to completion Learn about wallet-based payment processing Jump into the API documentation and begin building # Payment Lifecycle Source: https://docs.fincode.technology/deposit-engine/payment-lifecycle Understanding the lifecycle of a payment is crucial for integrating with the payment platform. This page details the various states a payment can traverse and the triggers for each transition. ## State Diagram The following diagram illustrates the standard flow of a payment from initiation to completion. ```mermaid theme={null} stateDiagram-v2 [*] --> PENDING_PAYMENT state "Payment Initiation" as Initiation { PENDING_PAYMENT --> CONFIRMED: Customer Initiates Payment PENDING_PAYMENT --> CANCELLED: Customer Cancels } state "Payment Processing" as Processing { CONFIRMED --> PAID: Payment Gateway Confirms CONFIRMED --> AWAITING_APPROVAL: Bank Transfer Initiated CONFIRMED --> FAILED: Payment Failed } state "Completion Phase" as Completion { PAID --> PAID_OUT: Transaction Completed AWAITING_APPROVAL --> PAID: Admin Confirms Bank Transfer AWAITING_APPROVAL --> CANCELLED: Payment Not Received } state "Terminal States" as Terminal { PAID_OUT --> [*] CANCELLED --> [*] FAILED --> REFUNDED REFUNDED --> [*] } note right of PENDING_PAYMENT Initial state when payable item is created end note note right of PAID_OUT Payment successfully processed and completed end note ``` ## Payment States ### 1. PENDING\_PAYMENT The initial state when a payable item is created and awaiting payment. * **Trigger**: Customer creates a transaction or wallet funding request * **Action Required**: Customer must select payment method and initiate payment * **Next Possible States**: `CONFIRMED`, `CANCELLED` View how to create payable items and fetch payment methods. ### 2. CONFIRMED Payment has been initiated but not yet verified by the payment gateway or admin. * **Trigger**: * Customer submits payment via wallet, card, or bank transfer * System creates payment instruction * **Context**: Payment is being processed by the gateway or awaiting bank transfer confirmation * **Next Possible States**: `PAID`, `AWAITING_APPROVAL`, `FAILED` ### 3. AWAITING\_APPROVAL Specific to bank transfers where customer has notified they will pay later. * **Trigger**: * Customer calls `PUT /bank-iwillpaylater-wallet/{pcn}/{payableType}` * Customer notifies `POST /notify-bank-transfer-payment` with option `bank_paid_now` * **Action Required**: * Customer makes offline bank transfer * Admin verifies payment receipt * **Next Possible States**: `PAID`, `CANCELLED` Initiate bank transfer payment Notify payment completion ### 4. PAID Payment has been successfully received and verified. * **Trigger**: * Payment gateway confirms successful payment * Admin confirms bank transfer received * Wallet debit successful * **Context**: Funds have been received and verified * **Next Possible States**: `PAID_OUT`, `REFUNDED` ### 5. PAID\_OUT Transaction has been completed successfully (final state for remittances). * **Trigger**: * For remittances: Funds disbursed to beneficiary * For wallet funding: Wallet credited * For bill payments: Payment confirmed by biller * **Action Required**: None - This is a terminal success state ### 6. FAILED Payment attempt failed due to insufficient funds, gateway error, or other issues. * **Trigger**: * Insufficient wallet balance * Card declined * Payment gateway error * Network timeout * **Action Required**: Customer may retry payment with different method * **Next Possible States**: `PENDING_PAYMENT`, `REFUNDED` ### 7. CANCELLED Payment was cancelled by customer or system. * **Trigger**: * Customer cancels before payment * Admin cancels awaiting payment * Automatic cancellation after timeout * **Action Required**: None - This is a terminal state ### 8. REFUNDED Payment was refunded to customer. * **Trigger**: * Transaction failed after payment received * Customer requested refund * Admin initiated refund * **Action Required**: None - This is a terminal state ### 9. HELD Payment is on hold pending investigation or compliance check. * **Trigger**: * Fraud detection alert * Compliance review required * Unusual transaction pattern * **Action Required**: Compliance team review * **Next Possible States**: `PAID`, `REFUNDED`, `CANCELLED` ### 10. SUSPENDED Payment or account suspended temporarily. * **Trigger**: * Account verification needed * Suspicious activity detected * Administrative hold * **Action Required**: Customer must resolve suspension reason * **Next Possible States**: `PENDING_PAYMENT`, `CANCELLED` ## Bank Transfer Lifecycle Bank transfers follow a specific workflow within the payment lifecycle: ```mermaid theme={null} flowchart TD A[Customer Initiates Transaction] --> B{Payment Method?} B -->|Bank Transfer| C[Customer Selects 'I Will Pay Later'] C --> D[System Creates Awaiting Payment Record] D --> E[Customer Makes Bank Transfer Offline] E --> F[Customer Notifies System] F --> G{Admin Verification} G -->|Payment Received| H[Status: PAID] G -->|Not Received| I[Status: CANCELLED] H --> J[Complete Transaction] style D fill:#f9f,stroke:#333 style G fill:#ff9,stroke:#333 style H fill:#9f9,stroke:#333 ``` ### Bank Transfer States | State | Description | Action Required | | :- | :- | :- | | `AWAITING_BANK_TRANSFER_PAYMENT` | Customer committed to pay via bank transfer | Customer makes transfer | | `RECEIVED_BANK_TRANSFER_PAYMENT` | Admin confirmed payment received | None | | `COMPLETED_PAYMENT_LIFECYCLE` | Payment verified and transaction completed | None | View and manage bank transfer payments awaiting confirmation. ## Payment Method Specific Flows ### Wallet Payment Flow ``` PENDING_PAYMENT → CONFIRMED → PAID → PAID_OUT ``` Wallet payments are typically instant if sufficient balance exists. Learn about wallet payment processing. ### Card Payment Flow ``` PENDING_PAYMENT → CONFIRMED → PAID → PAID_OUT ↓ FAILED ``` Card payments may fail due to insufficient funds or decline. Learn about card payment processing. ### Bank Transfer Flow ``` PENDING_PAYMENT → AWAITING_APPROVAL → PAID → PAID_OUT ↓ ↓ CANCELLED CANCELLED ``` Bank transfers require manual confirmation. Learn about bank transfer processing. ## State Transitions & Webhooks You can subscribe to webhook events to receive real-time updates when payment status changes. | Event Name | Description | | :- | :- | | `payment.initiated` | Triggered when status changes to CONFIRMED | | `payment.successful` | Triggered when payment is PAID | | `payment.failed` | Triggered when payment FAILED | | `payment.completed` | Triggered when status is PAID\_OUT | | `payment.refunded` | Triggered when payment is REFUNDED | | `payment.cancelled` | Triggered when payment is CANCELLED | Learn how to configure and handle webhook events. ## Payment Follow-up Actions For bank transfers, the system supports automated follow-up actions: ### Follow-up Action Types | Action Type | Description | | :- | :- | | `AUTO_CONFIRM_TRANSACTION` | Payment received and approved for payout | | `MARK_AS_PENDING_TRANSACTION` | Payment received but held | | `AUTO_HOLDFUND_WALLET` | Payment received and suspended | | `AUTO_FUND_WALLET` | Payment received and approved for funding | | `AUTO_WITHDRAWAL_WALLET` | Approved for payout | Manage awaiting payment follow-up actions. ## Best Practices ### Error Handling Always implement proper error handling for payment state transitions: ```javascript theme={null} try { const payment = await processPayment(paymentData); // Handle success if (payment.status === 'PAID') { completeTransaction(); } } catch (error) { // Handle specific payment errors if (error.code === 'INSUFFICIENT_FUNDS') { notifyCustomer('Please add funds to your wallet'); } else if (error.code === 'GATEWAY_ERROR') { suggestAlternativePaymentMethod(); } } ``` ### Status Monitoring Implement polling or webhooks to monitor payment status: ```javascript theme={null} // Polling approach const checkPaymentStatus = async (paymentId) => { const maxAttempts = 10; let attempts = 0; while (attempts < maxAttempts) { const status = await getPaymentStatus(paymentId); if (status === 'PAID' || status === 'FAILED') { return status; } await sleep(3000); // Wait 3 seconds attempts++; } throw new Error('Payment status timeout'); }; ``` ### User Experience * Show clear payment status to users * Provide estimated completion times * Offer alternative payment methods if first attempt fails * Send email/SMS notifications for status changes # Process Flow Source: https://docs.fincode.technology/deposit-engine/process-flows This guide details the complete payment processing flow, from payment method selection to transaction completion. The flow covers **Payment Method Selection**, **Wallet Payments**, **Bank Transfers**, and **Card Payments**. ## Phase 1: Payment Initiation & Method Selection ### 1.1 Get Supported Payment Methods Before processing any payment, retrieve available payment methods for the transaction. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant PaymentService Customer->>App: Initiate Payment App->>API: POST /supported-payment-methods API->>PaymentService: Query Payment Methods PaymentService->>PaymentService: Get Transaction Details PaymentService->>PaymentService: Check Available Gateways PaymentService->>PaymentService: Calculate Fees & Charges PaymentService-->>API: Return Payment Options API-->>App: Payment Methods with Charges App-->>Customer: Display Payment Options ``` Get available payment methods and charges Calculate payment method charges #### Payment Method Selection Steps Customer provides transaction details (PCN, amount, currency, payable type). System returns available payment methods based on: * **Country**: Customer's country and currency * **Amount**: Transaction amount and applicable limits * **Gateway**: Available payment gateway integrations * **Payable Type**: Type of transaction (TRANSACTION, WALLET, BILL, etc.) System calculates for each method: * **Principal Amount**: Base transaction amount * **Fee**: Transaction fee * **Tax**: Applicable taxes * **Exchange Rate**: For currency conversions * **Total Checkout Amount**: Complete amount customer will pay Customer reviews payment options with transparent pricing and selects preferred method. ## Phase 2: Wallet Payments ### 2.1 Pay from Wallet Account Process payments directly from customer's wallet balance. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant WalletService participant LedgerService Customer->>App: Select Wallet Payment App->>API: POST /makepaymentfromwalletaccount API->>WalletService: Process Wallet Payment WalletService->>WalletService: Validate Payable Item WalletService->>WalletService: Check Wallet Balance WalletService->>WalletService: Verify OTP/PIN (if required) WalletService->>LedgerService: Debit Wallet Account LedgerService-->>WalletService: Debit Successful WalletService->>WalletService: Update Payment Status WalletService-->>API: Payment Complete API-->>App: Payment Confirmation App-->>Customer: Transaction Success ``` Process payment from wallet Learn about wallet payments #### Wallet Payment Steps Customer provides: * **Payable ID**: Transaction identifier * **Payable Type**: Type of payment * **Account Number**: Wallet account (optional) * **Password**: Customer password * **OTP/PIN**: One-time password or PIN (if enabled) System validates: * Payable item exists and is pending * Customer authentication * Strong customer authentication (if enabled) * Transaction PIN (if required) System verifies: * Sufficient wallet balance * Account is active * No holds or restrictions System executes: * Debits wallet account * Updates payable status to PAID * Records transaction in ledger * Triggers payment completion workflow Customer receives confirmation with updated wallet balance. ## Phase 3: Bank Transfer Payments ### 3.1 Bank Transfer ("I Will Pay Later") Handle offline bank transfer payments with manual confirmation. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant PaymentService participant Admin Customer->>App: Select Bank Transfer App->>API: PUT /bank-iwillpaylater-wallet/{pcn}/{payableType} API->>PaymentService: Create Awaiting Payment PaymentService->>PaymentService: Record Payment Intent PaymentService-->>API: Awaiting Payment ID API-->>App: Bank Details + Reference App-->>Customer: Display Bank Details Customer->>Customer: Make Bank Transfer Offline Customer->>App: Notify Payment Made App->>API: POST /notify-bank-transfer-payment API->>PaymentService: Update Payment Status PaymentService->>Admin: Notify Admin for Verification Admin->>PaymentService: Verify & Confirm Payment PaymentService->>PaymentService: Update Status to PAID PaymentService-->>Customer: Payment Confirmed ``` Notify intent to pay via bank transfer Confirm bank transfer completed Learn about bank transfer workflow #### Bank Transfer Steps Customer selects "I Will Pay Later" option, providing PCN and payable type. System creates awaiting payment record with: * **Status**: AWAITING\_BANK\_TRANSFER\_PAYMENT * **Payment Reference**: Unique reference for bank transfer * **Bank Details**: Organization's bank account details * **Amount**: Total amount to transfer Customer completes bank transfer offline using provided: * Bank account number * Payment reference * Exact amount Customer notifies system via one of three options: * **bank\_paid\_now**: Payment already made * **bank\_pay\_later**: Will pay and notify later * **mistake**: Accidentally selected this method Admin reviews bank statement and verifies: * Payment received * Correct amount * Correct reference * Updates status to PAID System completes the transaction and processes the payable item. ### 3.2 View Awaiting Payments Admins can view and manage payments awaiting confirmation. ```mermaid theme={null} sequenceDiagram participant Admin participant App participant API participant PaymentService Admin->>App: View Awaiting Payments App->>API: GET /awaiting-payments API->>PaymentService: Query Awaiting Payments PaymentService->>PaymentService: Filter by Date/Currency PaymentService-->>API: Payment List API-->>App: Display Awaiting Payments App-->>Admin: Show Payment Details Admin->>App: Take Action (Confirm/Cancel) App->>API: POST /awaiting-payment-actions API->>PaymentService: Update Payment Status PaymentService-->>API: Action Complete API-->>App: Status Updated ``` View payments awaiting confirmation Manage awaiting payments ## Phase 4: Card Payments ### 4.1 Process Card Payment Process payments using credit or debit cards through payment gateways. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant PaymentGateway participant PaymentService Customer->>App: Enter Card Details App->>API: POST /process-card-payment API->>PaymentGateway: Submit Payment Request PaymentGateway->>PaymentGateway: Validate Card PaymentGateway->>PaymentGateway: Process Payment PaymentGateway-->>API: Payment Response API->>PaymentService: Update Payment Status PaymentService->>PaymentService: Record Transaction PaymentService-->>API: Payment Confirmed API-->>App: Payment Result App-->>Customer: Show Success/Failure ``` Process credit/debit card payment Learn about card payment processing #### Card Payment Steps Customer provides: * **Card Number (PAN)**: Primary account number * **Expiry Date**: Card expiration (MM/yyyy) * **Security Code**: CVV/CVC * **Amount**: Payment amount * **Currency**: Transaction currency System submits to payment gateway (e.g., SecureTrading): * Validates card details * Checks available balance * Performs fraud checks * Processes authorization Payment gateway returns: * **Transaction Reference**: Gateway transaction ID * **Status**: Success, failed, or requires 3DS * **Auth Code**: Authorization code * **Error Details**: If payment failed System updates payable item status based on gateway response: * **Success**: Status → PAID * **Failed**: Status → FAILED * **3DS Required**: Redirect for authentication Customer receives payment confirmation or error details. ### 4.2 Process with Payment Token For returning customers, process payments using saved payment tokens. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant PaymentGateway participant PaymentService Customer->>App: Select Saved Card App->>API: POST /processpaymentwithpaymenttoken API->>PaymentGateway: Verify Payment Token PaymentGateway-->>API: Token Valid API->>PaymentGateway: Process Payment PaymentGateway-->>API: Payment Response API->>PaymentService: Update Status PaymentService-->>API: Complete API-->>App: Payment Confirmed App-->>Customer: Success ``` Process payment with saved token ## Complete Payment Flow ```mermaid theme={null} flowchart TD Start([Start Payment]) --> GetMethods[Get Supported Payment Methods] GetMethods --> SelectMethod{Select Payment Method} SelectMethod -->|Wallet| CheckBalance{Sufficient Balance?} CheckBalance -->|Yes| ProcessWallet[Process Wallet Payment] CheckBalance -->|No| Error1[Insufficient Balance] ProcessWallet --> Success1[Payment Complete] SelectMethod -->|Bank Transfer| CreateAwaiting[Create Awaiting Payment] CreateAwaiting --> ShowBankDetails[Display Bank Details] ShowBankDetails --> CustomerTransfer[Customer Makes Transfer] CustomerTransfer --> NotifyPayment[Notify Payment Made] NotifyPayment --> AdminVerify{Admin Verifies?} AdminVerify -->|Confirmed| Success2[Payment Complete] AdminVerify -->|Rejected| Error2[Payment Rejected] SelectMethod -->|Card| ValidateCard{Card Valid?} ValidateCard -->|Yes| ProcessCard[Process Card Payment] ValidateCard -->|No| Error3[Invalid Card] ProcessCard --> GatewayResponse{Gateway Response?} GatewayResponse -->|Success| Success3[Payment Complete] GatewayResponse -->|Failed| Error4[Payment Failed] GatewayResponse -->|3DS| Authenticate[3DS Authentication] Authenticate --> Success3 Success1 --> End([End]) Success2 --> End Success3 --> End Error1 --> Retry{Retry?} Error2 --> Retry Error3 --> Retry Error4 --> Retry Retry -->|Yes| GetMethods Retry -->|No| End ``` ## Key Concepts ### Payment Methods The system supports multiple payment methods: * **E\_WALLET**: Instant payment from wallet balance * **BANK\_TRANSFER**: Offline bank transfer with confirmation * **ONLINE\_CARD\_PAYMENT**: Credit/debit card via gateway * **ONLINE\_BANK\_TRANSFER**: Direct online banking * **MOBILE\_MONEY**: Mobile money payments * **CRYPTO\_CURRENCY**: Cryptocurrency payments ### Payable Types Different transaction types that can be paid: * **TRANSACTION**: Money transfer/remittance * **WALLET**: Wallet funding * **WALLET\_CUSTOMER**: Personal wallet payment * **BILL**: Bill payment * **MERCHANT**: Product purchase * **VOUCHER**: Voucher purchase ### Payment Status Flow ``` PENDING_PAYMENT → CONFIRMED → PAID → PAID_OUT ``` For bank transfers: ``` PENDING_PAYMENT → AWAITING_APPROVAL → PAID → PAID_OUT ``` ### Charges & Fees Every payment includes: * **Principal Amount**: Base transaction amount * **Fee**: Service/transaction fee * **Tax**: Applicable taxes (VAT, etc.) * **Payment Method Fee**: Gateway/method specific fee * **Exchange Rate Fee**: For currency conversions * **Total Checkout Amount**: Complete amount charged ### Security Features * **Strong Customer Authentication (SCA)**: OTP verification for sensitive transactions * **Transaction PIN**: Additional PIN verification * **Payment Token**: Secure tokenization for saved cards * **3D Secure**: Card authentication for online payments * **Idempotency**: Prevent duplicate payment processing Explore all payment API endpoints and integration options. # Wallet Payments Source: https://docs.fincode.technology/deposit-engine/wallet-payments Wallet payments allow customers to pay instantly using their wallet balance. This is typically the fastest payment method and is fully integrated within the platform. ## Wallet Payment Flow ```mermaid theme={null} flowchart TD A[PENDING_PAYMENT] --> B[CONFIRMED] B --> C[PAID] C --> D[PAID_OUT] B --> E[FAILED] ``` ### Key Features * **Instant Payment**: Wallet balance is debited immediately. * **No Third-Party Gateway Required**: Fully internal processing. * **Integrated Tracking**: Payment status updates in real-time. * **Fallback Options**: Customer can top up wallet if insufficient balance. ### API Endpoints * **Make Payment from Wallet** ```http theme={null} POST /makepaymentfromwalletaccount ``` * **Get Wallet Balance** ```http theme={null} GET /wallet/balance ``` ### Integration Example ```json theme={null} { "pcn": "PCN123456", "payAbleType": "WALLET", "amount": "100.00", "currency": "USD" } ``` ### Best Practices * Ensure the customer has sufficient balance before initiating payment. * Handle `FAILED` status by prompting the customer to top up. * Poll or subscribe to wallet transaction webhooks for real-time updates. Learn how to create a payable item and pay via wallet. ``` ``` # Welcome to FinCode Source: https://docs.fincode.technology/index Enterprise-grade multitenant platform for remittance, digital lending, investment services, and crossboarder transaction switching. FinCode Platform Hero FinCode Platform Hero ## What is FinCode? FinCode is a comprehensive multitenant financial services platform that powers remittance, digital lending, and investment operations. Built for scale, security, and complete tenant isolation, FinCode enables financial institutions, fintech companies, and money service businesses to launch and manage their services with enterprise-grade infrastructure. Whether you're a bank looking to expand your digital offerings, a fintech startup building your first product, or an MSB seeking to modernize your operations, FinCode provides the infrastructure you need to succeed. Get your integration running in under 10 minutes with our step-by-step guide. Learn about Server-to-Server auth, JWT tokens, and tenant-scoped access. Understand our multitenant architecture and security model. Explore our comprehensive API documentation with examples. ## Core Products Cross-border money transfers with competitive FX rates, real-time tracking, and multi-corridor support. Automated loan underwriting, disbursement, and repayment management. Portfolio management, asset allocation, and investment tracking with real-time analytics. ## Platform Features Complete data isolation with tenant-specific configurations, branding, and business logic. Each tenant operates in a secure, isolated environment with customizable workflows and fee structures. Granular permissions for managers, agents, and end customers. Define custom roles, workflows, and approval chains per tenant with full audit trails. Instant transaction processing, real-time FX rates, automated loan decisions, and immediate settlement capabilities powered by our Songhai Exchange (SHE) switching platform. RESTful APIs with webhook support, detailed documentation, and interactive testing. Built for developers with clear error handling and extensive code examples. Built-in KYC/AML checks, transaction monitoring, regulatory reporting, and enterprise-grade security with encryption at rest and in transit. Real-time dashboards, transaction analytics, tenant performance metrics, and customizable reports for operational insights. ## Developer Resources OAuth 2.0, API keys, and tenant-scoped tokens for secure API access. Comprehensive error codes, retry logic, and troubleshooting guides. ## Get Started in 4 Steps Generate your API keys and configure OAuth 2.0 for secure access. [Get Started →](/authentication) Follow our quickstart guide to process your first remittance. [Quick Start →](/quickstart) Set up real-time notifications for transaction events. [Configure Webhooks →](/api/webhooks) *** ## Need Help? Check real-time system uptime. Contact our technical support team. Explore SDKs and code examples. # Encryption Keys & API Tokens Source: https://docs.fincode.technology/integration/encryption-keys-and-tokens Secure your integration with payload encryption and long-lived API tokens. FinCode provides two complementary security mechanisms for integration: 1. **Encryption Keys** - Public/private key pairs for encrypting sensitive data in API payloads 2. **API Tokens** - Long-lived authentication tokens for server-to-server communication Both are managed from your dashboard and available immediately upon onboarding. ## Encryption Keys ### Overview When integrating with FinCode, you may need to send sensitive information such as passwords, PINs, or other secrets. To protect this data during transmission, we provide RSA public key encryption. Your public and private key pair is automatically generated when your organization is onboarded and is always available on the settings area of your dashboard. ### How It Works ```mermaid theme={null} sequenceDiagram participant Dashboard participant Your Server participant FinCode API Dashboard->>Your Server: Copy Public Key Your Server->>Your Server: Encrypt sensitive fields (RSA-OAEP SHA-256) Your Server->>FinCode API: Send request with encrypted payload FinCode API->>FinCode API: Decrypt using Private Key FinCode API-->>Your Server: Process and respond ``` ### Key Management Your encryption keys are available on your dashboard under **Settings → API Connections → Encryption Keys**. You can rotate your key pair at any time from the dashboard. After rotation, the previous keys are immediately invalidated. ### When to Use Encryption Encrypt any sensitive fields before including them in your API request payload: | Field Type | Examples | Encryption Required | | - | - | - | | Passwords | `currentPassword`, `newPassword` | ✅ Yes | | PINs | `transactionPin`, `userPin` | ✅ Yes | | Security Answers | `securityAnswer` | ✅ Yes | | Regular Data | `email`, `firstName`, `amount` | ❌ No | ### Implementation The encryption uses **RSA with OAEP padding (SHA-256)**. Here's a quick reference: 1. Obtain your RSA public key from the dashboard (Base64 encoded) 2. Decode the Base64 key into an RSA PublicKey object 3. Initialize the cipher with `RSA/ECB/OAEPWithSHA-256AndMGF1Padding` 4. Encrypt the plaintext and Base64-encode the result 5. Send the encrypted value in your API request ```java theme={null} public static String encryptPayload(String payload, String publicKeyBase64) { try { byte[] keyBytes = Base64.getDecoder().decode(publicKeyBase64); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(keySpec); Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); byte[] encryptedBytes = cipher.doFinal(payload.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(encryptedBytes); } catch (Exception e) { throw new IllegalStateException("RSA encryption failed", e); } } ``` ```javascript theme={null} const crypto = require('crypto'); function encryptPayload(payload, publicKeyBase64) { // Convert Base64 to PEM format const publicKeyPem = `-----BEGIN PUBLIC KEY-----\n${publicKeyBase64}\n-----END PUBLIC KEY-----`; const encrypted = crypto.publicEncrypt( { key: publicKeyPem, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: 'sha256', }, Buffer.from(payload, 'utf8') ); return encrypted.toString('base64'); } ``` ```python theme={null} from cryptography.hazmat.primitives import serialization, hashes from cryptography.hazmat.primitives.asymmetric import padding import base64 def encrypt_payload(payload: str, public_key_base64: str) -> str: # Decode the Base64 public key key_bytes = base64.b64decode(public_key_base64) public_key = serialization.load_der_public_key(key_bytes) # Encrypt with OAEP padding encrypted = public_key.encrypt( payload.encode('utf-8'), padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None ) ) return base64.b64encode(encrypted).decode('utf-8') ``` ```csharp theme={null} using System; using System.Security.Cryptography; using System.Text; public static string EncryptPayload(string payload, string publicKeyBase64) { byte[] keyBytes = Convert.FromBase64String(publicKeyBase64); using (RSA rsa = RSA.Create()) { rsa.ImportSubjectPublicKeyInfo(keyBytes, out _); byte[] encryptedBytes = rsa.Encrypt( Encoding.UTF8.GetBytes(payload), RSAEncryptionPadding.OaepSHA256 ); return Convert.ToBase64String(encryptedBytes); } } ``` You can see the payload encryption guide [here](/integration/payload-encryption-guide) or download it below. Download our comprehensive encryption guide with detailed code sample and best practices. **Important Security Notes:** * Never share your private key—only use the public key for encryption * Ensure payload size does not exceed RSA key limits * Only encrypt sensitive fields, not entire request bodies *** ## API Tokens ### Overview For server-to-server integrations, FinCode provides long-lived API tokens that allow you to authenticate without going through the login flow. These tokens are generated from your dashboard and can be used directly in API requests. API tokens are different from the JWT access tokens received from the login endpoint. They provide a simpler authentication method for backend services. ### Token vs JWT Authentication | Feature | API Token | JWT (Login) | | - | - | - | | Obtained from | Dashboard | Login endpoint | | Expiry options | 24 hours, 1 month, 3 months, 6 months, 1 year | 1 hour (with refresh) | | Use case | Server-to-server, scheduled jobs, integrations | User sessions, real-time apps | | Rotation | Manual from dashboard | Automatic via refresh token | | Multiple tokens | ✅ Yes (different services) | ❌ No | ### Token Management Navigate to **Settings → API Connections → API Tokens** on your dashboard. Click **Create New Token** and select your desired expiry period. Choose from the available expiry options: * **24 Hours** – For temporary or testing purposes * **1 Month** – Short-term integrations * **3 Months** – Standard integrations * **6 Months** – Extended integrations * **1 Year** – Long-term production services Enter cashier email and password. You'd need this for generating any token. Copy the generated token immediately. For security, the full token is only shown once. Include the token in the `X-Auth-Token` header of your API requests. ### Token Operations Create multiple tokens for different services or environments (dev, staging, production). Generate a new token to replace an existing one without service interruption. Immediately revoke or delete a token if compromised or no longer needed. ### Using API Tokens Include your API token in the `X-Auth-Token` header: ```bash theme={null} curl -X GET "https://{domain}.fincode.software/api/v6/services/your-endpoint" \ -H "Content-Type: application/json" \ -H "X-Auth-Token: your-api-token-here" \ -H "platform: fincode" \ -H "uuid: 200" ``` ### Best Practices Never hardcode API tokens in your source code. Store them in environment variables or a secrets manager. ```javascript theme={null} // ✅ Good const token = process.env.FINCODE_API_TOKEN; // ❌ Bad const token = "fc_live_abc123..."; ``` Create separate tokens for each service or environment. This limits the blast radius if a token is compromised. * `FINCODE_TOKEN_PROD` – Production services * `FINCODE_TOKEN_STAGING` – Staging environment * `FINCODE_TOKEN_CRON` – Scheduled jobs Regularly review which tokens are active and when they were last used. Revoke unused or dormant tokens. Set reminders before tokens expire. Implement graceful rotation to avoid service interruptions. ## Summary | Feature | Encryption Keys | API Tokens | | - | - | - | | Purpose | Protect sensitive payload data | Authenticate API requests | | Location | Dashboard → API Connections → Encryption Keys | Dashboard → API Connections → API Tokens | | Rotation | Available anytime | Available anytime | | When to use | Sending passwords, PINs, secrets | Server-to-server calls, webhooks, etc | *** ## Next Steps Learn about user authentication and JWT tokens Deep dive into FinCode's security architecture Test your integration in the sandbox environment Complete your integration checklist # Go Live Source: https://docs.fincode.technology/integration/go-live Congratulations on completing your integration! Before launching to production, follow this checklist to ensure a smooth and secure deployment. ## Pre-Launch Checklist ### Security Review * [ ] **Credentials Management**: Confirm API credentials are stored in environment variables * [ ] **HTTPS Only**: Ensure all API calls use HTTPS * [ ] **Token Security**: Implement secure token storage and automatic refresh * [ ] **Webhook Validation**: Verify webhook signature validation is implemented * [ ] **Error Logging**: Ensure sensitive data (tokens, passwords) is not logged ### Error Handling * [ ] **Network Failures**: Implement retry logic with exponential backoff * [ ] **Graceful Degradation**: Handle API downtime gracefully * [ ] **User Feedback**: Provide clear error messages to users * [ ] **Monitoring**: Set up alerts for critical errors ### Webhook Setup * [ ] **Endpoint Configured**: Production webhook URL is registered * [ ] **Idempotency**: Handle duplicate webhook deliveries * [ ] **Async Processing**: Process webhooks asynchronously to avoid timeouts * [ ] **Retry Handling**: Implement retry logic for failed webhook processing ### Compliance * [ ] **Data Privacy**: Ensure GDPR/NDPR compliance for user data * [ ] **Terms & Conditions**: Display payment terms to users * [ ] **Record Keeping**: Implement transaction audit logging ## Production Credentials To obtain production API credentials: 1. **Complete Integration Testing**: Ensure all test scenarios pass 2. **Submit Go-Live Request**: Email [hello@fincode.co.uk](mailto:hello@fincode.co.uk) with: * Company name and registration details * Integration completion confirmation * Expected transaction volume 3. **Receive Production Access**: You'll receive: * Production API credentials * Production base URL: `https://${domain}.fincode.tech` * Production webhook configuration ## Monitoring & Logging ### Recommended Metrics Track these key metrics to monitor your integration health: * **Transaction Success Rate**: Percentage of successful transactions * **API Response Times**: Monitor for degradation * **Error Rates**: Track 4xx and 5xx errors * **Webhook Delivery**: Monitor webhook receipt and processing times ### Logging Best Practices * Log all API requests and responses (excluding sensitive data) * Include correlation IDs for tracing * Set up alerts for: * High error rates (>5%) * Slow response times (>3 seconds) * Failed webhook deliveries ## Support ### Production Support For production issues, contact our support team: * **Email**: [hello@fincode.co.uk](mailto:hello@fincode.co.uk) ### What to Include in Support Requests * Transaction ID or Customer Code * Timestamp of the issue * Error message or response * Steps to reproduce ## Launch Day On launch day: 1. **Monitor Closely**: Watch logs and metrics for the first few hours 2. **Have Rollback Plan**: Be prepared to revert if critical issues arise 3. **Communicate**: Keep your team and stakeholders informed 4. **Celebrate**: You've successfully integrated with FinCode! 🎉 # Payload Encryption Guide Source: https://docs.fincode.technology/integration/payload-encryption-guide This document describes the steps required to encrypt sensitive payload data such as passwords before sending it to the FinCode API. The encryption ensures data confidentiality during transmission. We use **RSA public key encryption with OAEP padding (SHA-256)**. You will be provided with a Base64-encoded public key from your dashboard. Using this key, you must encrypt sensitive fields before sending them in your payload. ## Steps to Encrypt Payload 1. Obtain the RSA public key from your dashboard (Base64 encoded) 2. Convert the public key from Base64 into an RSA PublicKey object 3. Initialize an RSA cipher using OAEP with SHA-256 padding 4. Encrypt the plaintext payload (e.g., password) using UTF-8 encoding 5. Base64-encode the encrypted output 6. Send the encrypted value in your API request payload ## Code Examples ### Java ```java theme={null} import java.nio.charset.StandardCharsets; import java.security.KeyFactory; import java.security.PublicKey; import java.security.spec.X509EncodedKeySpec; import java.util.Base64; import javax.crypto.Cipher; public class PayloadEncryption { public static String encryptPayload(String payload, String publicKeyBase64) { try { // Decode the Base64 public key byte[] keyBytes = Base64.getDecoder().decode(publicKeyBase64); X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes); PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(keySpec); // Initialize cipher with OAEP padding Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding"); cipher.init(Cipher.ENCRYPT_MODE, publicKey); // Encrypt and encode byte[] encryptedBytes = cipher.doFinal(payload.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(encryptedBytes); } catch (Exception e) { throw new IllegalStateException("RSA encryption failed", e); } } // Usage example public static void main(String[] args) { String publicKey = "YOUR_BASE64_PUBLIC_KEY"; String password = "user-password-123"; String encryptedPassword = encryptPayload(password, publicKey); System.out.println("Encrypted: " + encryptedPassword); } } ``` ### JavaScript (Node.js) ```javascript theme={null} const crypto = require('crypto'); function encryptPayload(payload, publicKeyBase64) { // Convert Base64 to PEM format const publicKeyPem = `-----BEGIN PUBLIC KEY-----\n${publicKeyBase64}\n-----END PUBLIC KEY-----`; const encrypted = crypto.publicEncrypt( { key: publicKeyPem, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING, oaepHash: 'sha256', }, Buffer.from(payload, 'utf8') ); return encrypted.toString('base64'); } // Usage example const publicKey = 'YOUR_BASE64_PUBLIC_KEY'; const password = 'user-password-123'; const encryptedPassword = encryptPayload(password, publicKey); console.log('Encrypted:', encryptedPassword); ``` ### Python ```python theme={null} from cryptography.hazmat.primitives import serialization, hashes from cryptography.hazmat.primitives.asymmetric import padding import base64 def encrypt_payload(payload: str, public_key_base64: str) -> str: """ Encrypt a payload using RSA with OAEP padding (SHA-256). Args: payload: The plaintext string to encrypt public_key_base64: Base64-encoded RSA public key Returns: Base64-encoded encrypted string """ # Decode the Base64 public key key_bytes = base64.b64decode(public_key_base64) public_key = serialization.load_der_public_key(key_bytes) # Encrypt with OAEP padding encrypted = public_key.encrypt( payload.encode('utf-8'), padding.OAEP( mgf=padding.MGF1(algorithm=hashes.SHA256()), algorithm=hashes.SHA256(), label=None ) ) return base64.b64encode(encrypted).decode('utf-8') # Usage example if __name__ == "__main__": public_key = "YOUR_BASE64_PUBLIC_KEY" password = "user-password-123" encrypted_password = encrypt_payload(password, public_key) print(f"Encrypted: {encrypted_password}") ``` **Required package:** `pip install cryptography` ### C# (.NET) ```csharp theme={null} using System; using System.Security.Cryptography; using System.Text; public class PayloadEncryption { public static string EncryptPayload(string payload, string publicKeyBase64) { // Decode the Base64 public key byte[] keyBytes = Convert.FromBase64String(publicKeyBase64); using (RSA rsa = RSA.Create()) { // Import the public key rsa.ImportSubjectPublicKeyInfo(keyBytes, out _); // Encrypt with OAEP SHA-256 padding byte[] encryptedBytes = rsa.Encrypt( Encoding.UTF8.GetBytes(payload), RSAEncryptionPadding.OaepSHA256 ); return Convert.ToBase64String(encryptedBytes); } } // Usage example public static void Main() { string publicKey = "YOUR_BASE64_PUBLIC_KEY"; string password = "user-password-123"; string encryptedPassword = EncryptPayload(password, publicKey); Console.WriteLine($"Encrypted: {encryptedPassword}"); } } ``` ## API Request Example Once you have the encrypted value, include it in your API request: ```json theme={null} { "email": "user@example.com", "currentPassword": "BASE64_ENCRYPTED_PASSWORD_HERE" } ``` **Using cURL:** ```bash theme={null} curl -X PUT "https://{domain}.fincode.software/api/v6/services/securitymanagement/login" \ -H "Content-Type: application/json" \ -H "platform: fincode" \ -H "uuid: 200" \ -d '{ "email": "user@example.com", "currentPassword": "BASE64_ENCRYPTED_PASSWORD_HERE" }' ``` ## Important Notes 1. **Payload Size Limit**: RSA encryption has a maximum payload size based on key length. For a 2048-bit key, the maximum is approximately 190 bytes. Only encrypt individual sensitive fields, not entire request bodies. 2. **Public Key Only**: Never share your private key. Only the public key should be used for encryption on your side. 3. **Key Rotation**: When you rotate your keys on the dashboard, update your integration with the new public key immediately. 4. **Encoding**: Always use UTF-8 encoding for the plaintext before encryption. 5. **Transport Security**: While encryption protects the data in the payload, always use HTTPS for all API communications. ## Troubleshooting | Issue | Cause | Solution | | - | - | - | | Decryption fails | Wrong key used | Verify you're using the current public key from dashboard | | Padding error | Incorrect cipher mode | Ensure using `OAEPWithSHA-256AndMGF1Padding` | | Key format error | Base64 decode issue | Check for line breaks or spaces in the key | | Size limit exceeded | Payload too large | Only encrypt individual fields, not entire bodies | *** ## Need Help? If you encounter any issues with payload encryption, please contact our support team or refer to the [Authentication documentation](/authentication) for more details. # Payment Methods Source: https://docs.fincode.technology/integration/payment-methods FinCode supports multiple payment methods to facilitate transaction funding. This guide details the integration flows for **Card Payments (Hosted Checkout)** and **Open Banking**. ## Supported Payment Methods To retrieve the available payment methods for a specific transaction, use the `supported-payment-methods` endpoint. This endpoint returns the payment options configured for your tenant and the specific corridor. Get Supported Payment Methods ### Response Schema The response includes a list of `paymentMethodsMetadata`, each containing specific details for that provider. ```json theme={null} { "status": "SUCCESS", "data": { "paymentTermsNConditions": "https://your-terms-url.com", "paymentMethodsMetadata": [ { "provider": "VOLUME", "type": "ONLINE_BANK_PAYMENT", "paymentDetails": { "paymentIntentId": "9b9f23a3-d7c8-4cd7-aa18-e3bfd32e4ef6", "hosted_gateway_url": "https://paybylink.volumepay.io/?paymentIntentId=..." }, "hosted": true, "principalAmount": 2.00, "total-amount": 2.47 }, { "provider": "SECURE_TRADING", "type": "ONLINE_CARD_PAYMENT", "paymentDetails": { "sitereference": "remitjunction126902", "orderreference": "TR656516344451", "allurlnotification": "https://.../webhook/payment/notify", "mainamount": "2.42", "currencyiso3a": "GBP", "version": "2" }, "hosted": true, "principalAmount": 2.00, "total-amount": 2.42 } ] } } ``` ## Card Payments (Hosted Checkout) We support hosted card checkout flows via providers like **TrustPayments (Secure Trading)** and **PayCross**. **No Card Saving**: FinCode does **NOT** support saving or vaulting card details for these hosted flows. Please do not implement "Save Card" functionality in your UI. ### HTML Form Injection TrustPayments requires a hidden HTML form to be constructed and submitted from the client side. **Integration Flow:** 1. **Initiate Transaction**: Create a transaction and call `supported-payment-methods`. 2. **Select Provider**: Choose `SECURE_TRADING`. 3. **Construct Form**: Create a hidden HTML form using **all** key-value pairs from the `paymentDetails` object. 4. **Auto-Submit**: POST the form to `https://payments.securetrading.net/process/payments/choice`. 5. **Redirect**: User is redirected to the secure payment page. 6. **Watch for Redirect**: Listen for the callback URL (e.g., `http://remitter.test.remitjunction.io/`) to detect completion. **Dart / Flutter Example:** ```dart theme={null} String _buildTrustPaymentFormHtml() { return '''
Redirecting to secure payment...
${widget.paymentData?.entries.map((e) => '').join('')}
'''; } ```
### Hosted URL Redirect Other providers like PayCross typically provide a direct URL to redirect the user to. **Integration Flow:** 1. **Initiate Transaction**: Create a transaction and call `supported-payment-methods`. 2. **Select Provider**: Choose the provider (e.g., `PAYCROSS`). 3. **Redirect User**: Use the `hosted_gateway_url` (or similar field) from `paymentDetails` to redirect the user's browser or webview. 4. **Completion**: Watch for the callback URL to detect when the user returns to your app. **Example Response:** ```json theme={null} { "provider": "PAYCROSS", "type": "ONLINE_CARD_PAYMENT", "paymentDetails": { "hosted_gateway_url": "https://paycross.com/checkout/..." } } ```
## Open Banking Open Banking payments are facilitated via providers like **Volume** and **Volt**. This flow typically uses a deep link or a redirect URL. ### Integration Flow 1. **Initiate Transaction**: Create a transaction and get the supported payment methods. 2. **Select Provider**: Choose the `ONLINE_BANK_PAYMENT` provider (e.g., `VOLUME`). 3. **Redirect User**: Use the `hosted_gateway_url` from the `paymentDetails` to redirect the user. * **Web**: Redirect the browser window. * **Mobile**: Launch the URL, which may open the user's banking app via deep link. 4. **Completion**: After payment, the user is redirected back to your application (configured via the callback URLs). ### Example Response Data ```json theme={null} { "provider": "VOLUME", "type": "ONLINE_BANK_PAYMENT", "paymentDetails": { "paymentIntentId": "9b9f23a3-d7c8-4cd7-aa18-e3bfd32e4ef6", "hosted_gateway_url": "https://paybylink.volumepay.io/?paymentIntentId=9b9f23a3-d7c8-4cd7" } } ``` *** ## Webhooks & Status Updates Since these are hosted flows, your application will not receive the payment result synchronously in the response. You must listen for Webhooks to update the transaction status. * **Success**: The provider calls the `allurlnotification` (or configured webhook URL). FinCode processes this and updates the transaction status to `PAID` or `PROCESSING`. * **Failure**: If payment fails, the status will be updated to `FAILED` or `CANCELLED`. Learn how to subscribe to transaction status events. # Testing Source: https://docs.fincode.technology/integration/testing Before deploying to production, it's critical to thoroughly test your integration in our sandbox environment. This ensures a smooth launch and helps identify potential issues early. ## Test Environment Our sandbox environment mirrors production functionality but uses test credentials and does not process real money. **Base URL**: `https://${domain}.fincode.software` ### Getting Test Credentials 1. Contact your account manager or email [hello@fincode.co.uk](mailto:hello@fincode.co.uk) 2. You'll receive: * Test API credentials (email/password) * Test customer/payment codes * Sandbox domain ### Test Payment Methods #### Test Cards (Hosted Checkout) Use these test card numbers with any future expiry date and any 3-digit CVV: | Card Number | Expected Result | | - | - | | `4111 1111 1111 1111` | Success | | `4000 0000 0000 0002` | Declined | #### Test Bank Accounts For bank transfer testing: | Country | Bank Code | Account Number | Expected Result | | - | - | - | - | | NGA | `214` | `1234567890` | Validation supported, success | | NGA | `214` | `0000000000` | Validation fails | ## Testing Checklist Work through these scenarios to ensure your integration is robust: ### Core Flows * [ ] **Successful Transaction**: Create and complete a full transaction from quote to payment * [ ] **Failed Payment**: Handle declined card or failed bank transfer * [ ] **Compliance Rejection**: Test with flagged customer data (contact support for test cases) * [ ] **Beneficiary Creation**: Create beneficiaries for all types (Bank, Cash, Mobile Money) * [ ] **Account Validation**: Test both supported and unsupported validation scenarios ### Error Handling * [ ] **Invalid Credentials**: Verify proper handling of 401 errors * [ ] **Expired Token**: Test token refresh flow * [ ] **Network Timeout**: Simulate slow/failed requests * [ ] **Invalid Input**: Test validation errors (e.g., invalid country code) ### Webhooks * [ ] **Webhook Receipt**: Confirm your server receives webhook events * [ ] **Signature Validation**: Verify webhook authenticity * [ ] **Idempotency**: Handle duplicate webhook deliveries ## Common Issues **Cause**: Expired or invalid access token. **Solution**: Implement automatic token refresh using the refresh token before it expires. **Cause**: The payout partner for the selected corridor doesn't support account validation. **Solution**: Allow users to proceed without validation and manually enter beneficiary details. **Cause**: Webhook URL not configured or firewall blocking requests. **Solution**: * Verify webhook URL is publicly accessible * Check firewall rules allow FinCode IPs * Test with a tool like webhook.site first ## Next Steps Once you've completed testing, proceed to the [Go-Live](/integration/go-live) checklist. # Account Opening Source: https://docs.fincode.technology/investment/account-opening This guide provides a detailed, step-by-step walkthrough of the investment account opening process, from product selection to your first investment. The account opening process includes **Product Selection**, **Quote Generation**, **Investment Application**, **Wallet Creation**, and **Funding**. ## Overview Opening an investment account involves selecting a product, getting a quote, submitting your investment application. The system automatically creates a wallet for you, which you then fund to complete the investment. This guide walks you through each step. ## Step 1: Browse Investment Products ### Why Fund the Wallet? Before making investments, you need to add funds to your wallet. The investment amount (including fees) will be deducted from your wallet balance when you submit an investment application. ### Funding Process ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant WalletService Customer->>App: Request to Fund Wallet App->>API: PUT /wallet/fund-wallet/{wallet-id}/{amount} Note over API: Request includes:
- Wallet ID
- Amount to Add API->>WalletService: Process Funding WalletService->>WalletService: Validate Wallet WalletService->>WalletService: Credit Wallet WalletService->>WalletService: Update Balance WalletService-->>API: Funding Confirmed API-->>App: Return Success App-->>Customer: Balance Updated ``` View the complete API documentation for funding wallets. ### Funding Steps Choose the wallet you want to fund. If you have multiple wallets, select the one in the currency you plan to invest in. Enter the amount you want to add to the wallet. This should be sufficient to cover your planned investment plus any applicable fees. The system credits your wallet with the specified amount. The balance is updated immediately. Confirm that your wallet balance has been updated correctly before proceeding to make an investment. ### Funding Request Example ```bash theme={null} PUT /api/v1/user/wallet/fund-wallet/{wallet-id}/{amount} # Example: PUT /api/v1/user/wallet/fund-wallet/123e4567-e89b-12d3-a456-426614174000/100000 ``` Ensure your wallet has sufficient balance before submitting an investment application. Applications with insufficient funds will be rejected. ### Understanding Investment Products Investment products define the terms and conditions for different types of investments: * **Fixed Investments**: Corporate bonds with fixed terms and returns * **Dynamic Investments**: Mutual funds with variable returns * **Risk Profiles**: Conservative, Moderate, and Aggressive options * **APY (Annual Percentage Yield)**: The interest rate for the investment * **Maturity Terms**: Investment periods with maturity dates ### Product Selection Considerations When selecting an investment product, consider: * **Risk Tolerance**: Choose products that match your risk profile * **Investment Amount**: Ensure the product accepts your desired investment amount * **Maturity Period**: Consider how long you want to invest * **APY**: Compare interest rates across different products * **Currency**: Ensure the product matches your wallet currency Product availability and terms may vary. Always review product details and terms before making an investment decision. ## Step 2: Get Investment Quote ### What is a Quote? A quote provides a detailed breakdown of the costs and amounts for purchasing a specific number of units of an investment product. It includes: * **Unit Price**: Price per unit of the investment * **Number of Units**: Quantity you want to purchase * **Fees**: Applicable fees for the investment * **Total Amount**: Total cost including fees * **Investing Amount**: Net amount to be invested ### Quote Request Process ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant QuoteService participant ProductService Customer->>App: Select Product & Units App->>API: GET /quote/get-quote/{product-id}/{units} API->>ProductService: Get Product Details ProductService-->>API: Product Information API->>QuoteService: Calculate Quote QuoteService->>QuoteService: Calculate Unit Price QuoteService->>QuoteService: Calculate Fees QuoteService->>QuoteService: Calculate Total QuoteService-->>API: Quote Details API-->>App: Return Quote App-->>Customer: Display Quote Breakdown ``` View the complete API documentation for getting quotes. ### Quote Request Example ```bash theme={null} GET /api/v1/user/quote/get-quote/{product-id}/{number-of-units-to-purchase} # Example: GET /api/v1/user/quote/get-quote/11d936b5-f6db-45d6-b35e-2ce24791997f/100 ``` ### Quote Response Example ```json theme={null} { "status": "SUCCESS", "data": { "productId": "11d936b5-f6db-45d6-b35e-2ce24791997f", "numberOfUnits": 100, "unitPrice": 1000.00, "fees": 50.00, "totalAmount": 100050.00, "investingAmount": 100000.00 } } ``` ### Reviewing the Quote Before proceeding, review: * **Total Amount**: Ensure you have sufficient wallet balance * **Fees**: Understand what fees are being charged * **Investing Amount**: Confirm the net amount to be invested * **Unit Price**: Verify the price per unit Quotes are calculated in real-time. Prices may change, so submit your investment application promptly after receiving a quote. ## Step 3: Submit Investment Application ### Application Submission Once you've reviewed the quote and confirmed your wallet has sufficient balance, you can submit your investment application. ### Application Process ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant InvestmentService participant WalletService participant PortfolioService Customer->>App: Submit Application App->>API: POST /apply Note over API: Request includes:
- Product ID
- Number of Units
- Wallet ID
- Customer Info API->>InvestmentService: Process Application InvestmentService->>WalletService: Check Balance WalletService-->>InvestmentService: Balance Confirmed InvestmentService->>InvestmentService: Validate Application InvestmentService->>WalletService: Debit Wallet WalletService-->>InvestmentService: Debit Confirmed InvestmentService->>PortfolioService: Create Portfolio PortfolioService->>PortfolioService: Record Investment PortfolioService->>PortfolioService: Set Maturity Date PortfolioService-->>InvestmentService: Portfolio Created InvestmentService-->>API: Application Success API-->>App: Return Confirmation App-->>Customer: Investment Active ``` View the complete API documentation for creating investment applications. ### Application Request To submit an investment application, provide: * **Investment Product ID**: The product you want to invest in * **Number of Units to Purchase**: Quantity of units * **User Wallet ID**: Your wallet account ID (source of funds) * **Customer ID**: Your unique customer identifier * **Customer Name**: Your full name ### Application Request Example ```json theme={null} { "investmentProductId": "11d936b5-f6db-45d6-b35e-2ce24791997f", "numberOfUnitsToPurchase": 100, "userWalletId": "123e4567-e89b-12d3-a456-426614174001", "customerId": "123e4567-e89b-12d3-a456-426614174002", "customerName": "John Doe" } ``` ### Application Validation The system validates: 1. **Wallet Balance**: Sufficient funds in the specified wallet 2. **Product Availability**: Product is active and available 3. **Unit Quantity**: Valid number of units requested 4. **Customer Eligibility**: Customer meets product requirements ### What Happens After Submission A **wallet account** is automatically created for you in the currency of the investment product. You need to fund the wallet with the investment amount (including fees) to complete the investment. Once the wallet is funded, a new investment portfolio is created with your investment details. The system sets up automatic interest calculation and accrual based on the product's APY. You receive confirmation with your portfolio ID and investment details. ### Application Response Example ```json theme={null} { "status": "SUCCESS", "data": { "investmentApplicationId": "a1b2c3d4-e5f6-7890-1234-567890abcdef", "portfolioId": "b2c3d4e5-f6a7-8901-2345-678901bcdefg", "numberOfUnits": 100, "investmentAmount": 100000.00, "status": "ACTIVE" } } ``` Once your application is processed, your investment is active and interest begins accruing immediately based on the product's APY. ## Step 4: Wallet Creation & Funding ### Automatic Wallet Creation When you submit an investment application, a wallet account is automatically created for you. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant InvestmentService participant WalletService Customer->>App: Submit Investment Application App->>API: POST /apply API->>InvestmentService: Process Application InvestmentService->>WalletService: Create Wallet Automatically WalletService->>WalletService: Generate Account Number WalletService->>WalletService: Create Wallet Record WalletService-->>InvestmentService: Wallet Created InvestmentService-->>API: Wallet Ready API-->>App: Application Received App-->>Customer: Wallet Created ``` The wallet is automatically created in the currency of the investment product. No action is required from you for wallet creation. ### Fund Your Wallet After the wallet is created, you need to fund it to cover the investment amount. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant WalletService participant InvestmentService Customer->>App: Fund Wallet Request App->>API: PUT /wallet/fund-wallet/{wallet-id}/{amount} API->>WalletService: Process Funding WalletService->>WalletService: Credit Wallet WalletService-->>API: Funding Confirmed API->>InvestmentService: Process Investment InvestmentService->>WalletService: Debit Wallet WalletService-->>InvestmentService: Debit Confirmed InvestmentService->>InvestmentService: Create Portfolio InvestmentService-->>API: Portfolio Created API-->>App: Investment Active App-->>Customer: Investment Confirmed ``` View the complete API documentation for funding wallets. ### Funding Steps Your wallet is automatically created when you submit the investment application. Add funds to your wallet to cover the investment amount (including fees). Once the wallet is funded, the investment is processed and your portfolio is created. ## Complete Account Opening Flow ```mermaid theme={null} flowchart TD Start([Start Account Opening]) --> BrowseProducts[Browse Investment Products] BrowseProducts --> SelectProduct[Select Product] SelectProduct --> GetQuote[Get Quote] GetQuote --> ReviewQuote{Review Quote} ReviewQuote -->|Accept| SubmitApp[Submit Application] ReviewQuote -->|Reject| BrowseProducts SubmitApp --> CreateWallet[Wallet Created Automatically] CreateWallet --> FundWallet[Fund Wallet] FundWallet --> CheckBalance{Wallet Balance
Sufficient?} CheckBalance -->|Yes| ProcessApp[Process Investment] CheckBalance -->|No| FundWallet ProcessApp --> DebitWallet[Debit Wallet] DebitWallet --> CreatePortfolio[Create Portfolio] CreatePortfolio --> StartAccrual[Start Interest Accrual] StartAccrual --> Confirm[Send Confirmation] Confirm --> End([Account Opened
Investment Active]) ``` ## Next Steps After Account Opening Once your investment account is opened and your first investment is active: View all your investment portfolios Monitor your investment performance See your total investments and interest Understand the complete investment process See the complete investment process flow with detailed diagrams. Understand the trading and execution flow. # Overview Source: https://docs.fincode.technology/investment/overview Welcome to the investment platform documentation. This guide will help you understand how our investment management system works and how to integrate it into your application. ### What is Investment Management? Our investment platform enables **secure, flexible, and automated investment processing** for customers. The system supports: * **Investment Applications** - Customers can invest in various products through multiple channels * **Portfolio Management** - Track and manage multiple investment portfolios * **Interest Accrual** - Automated interest calculation and accrual * **Real-Time Tracking** - Monitor investments, returns, and performance ### Key Features Support for various investment products including fixed deposits, mutual funds, and corporate bonds with different risk profiles. Customers can invest in units, with flexible amounts and product selection based on their risk tolerance. Automatic interest accrual and calculation based on product terms and Annual Percentage Yield (APY). Comprehensive portfolio management with real-time tracking of investments, returns, and maturity dates. Secure wallet system for funding investments and receiving returns with multi-currency support. RESTful APIs with comprehensive documentation and sandbox environment for seamless integration. ### How It Works The investment flow consists of four main phases: Customers browse available investment products, get quotes for specific unit purchases, and review investment terms including fees and expected returns. Customers submit investment applications specifying the product, number of units, and other required details. The system processes and creates the investment portfolio. When an investment application is submitted, a **wallet account** is automatically created for the customer. Customers can fund their wallet to cover the investment amount. Customers can track their portfolios, view total investments, monitor interest accrual, and manage multiple investments through a unified dashboard. For detailed visual flow, see the [Account Opening](/investment/account-opening) and [Portfolio Management](/investment/portfolio-management) pages. ### Core Concepts #### Investment Products Investment products define the terms and conditions for different types of investments: * **Product Types** - Fixed deposits (corporate bonds) and Dynamic investments (mutual funds) * **Risk Profiles** - Conservative, Moderate, and Aggressive investment options * **Interest Rates** - Annual Percentage Yield (APY) for each product * **Unit-Based Pricing** - Investments are made in units with per-unit pricing * **Maturity Terms** - Fixed investment periods with maturity dates Understand how investment products are structured and selected. #### Investment Wallets Wallets are required for all investment operations: * **Multi-Currency Support** - Wallets can be created in different currencies (NGN, USD, GBP, etc.) * **Funding** - Funds can be added to wallets before making investments * **Secure Storage** - Funds are securely held until invested or withdrawn * **Transaction History** - Complete audit trail of all wallet operations Explore wallet creation and management processes. #### Portfolio Management Portfolios track customer investments: * **Multiple Portfolios** - Customers can have multiple investment portfolios * **Investment Details** - Track amount invested, total payable, APY, and product information * **Maturity Tracking** - Monitor request dates and due dates for each investment * **Performance Metrics** - View total investments and accrued interest across all portfolios Understand portfolio tracking and management features. #### Interest Accrual The platform automatically calculates and accrues interest: * **APY-Based Calculation** - Interest calculated based on Annual Percentage Yield * **Automatic Accrual** - Interest accrues automatically based on product terms * **Total Tracking** - View total interest accrued across all investments * **Currency-Specific** - Interest tracked per currency Explore interest calculation and performance tracking. ### Investment Application Process #### 1. Browse Products & Get Quote Customers explore available investment products: * View product details, APY, and terms * Get quotes for specific number of units * Review total amount, fees, and investing amount * Compare different products #### 2. Submit Investment Application Customers submit investment applications: * Select investment product * Specify number of units to purchase * Provide customer information * Application is processed #### 3. Wallet Creation & Funding When an investment application is submitted: * A **wallet account** is automatically created for the customer * The wallet is created in the currency of the investment product * Customers can fund their wallet to cover the investment amount * Once funded, the investment is processed and portfolio created #### 4. Portfolio Management Customers can: * View all their investment portfolios * Track total investments across all products * Monitor interest accrued * View individual portfolio details (amount invested, total payable, APY, maturity dates) Detailed step-by-step investment process flow. ### Supported Features #### Product Types * **Fixed Investments** - Corporate bonds with fixed terms and returns * **Dynamic Investments** - Mutual funds with variable returns * **Risk-Based Options** - Conservative, Moderate, and Aggressive investment profiles #### Quote System * Real-time quote calculation * Fee transparency * Unit-based pricing * Total cost breakdown #### Dashboard & Analytics * Total investments tracking * Interest accrued monitoring * Portfolio performance metrics * Multi-currency support Explore investment analytics and performance tracking. ### Integration Quick Start Before you begin: Contact our team to receive your sandbox API keys and base URL. Familiarize yourself with our [Investment API Reference](/api/investment/create-investment-application). Read through the [Account Opening](/investment/account-opening) process to understand the complete investment journey. Explore all available investment endpoints with request/response examples. ### Testing & Sandbox We provide a full-featured sandbox environment for testing: * **Sandbox URL**: `https://test-investment-products-service.fincode.software` * **Test credentials**: Provided upon registration * **Mock transactions**: Simulate investment operations * **No real money**: All transactions are simulated Use the sandbox to test all flows, edge cases, and error handling before going live. ### Integration Models We support flexible integration approaches: ### End-to-End Integration Build the complete investment experience within your application, managing the entire customer journey from wallet creation to portfolio management. **Flow**: 1. Customer registration and KYC 2. Wallet creation and funding 3. Product selection and quote 4. Investment application submission 5. Portfolio management and tracking **Documentation**: * [Account Opening Process](/investment/account-opening) * [Create Investment Application API](/api/investment/create-investment-application) * [Authentication](/api/auth/login) ### Direct API Integration If you manage your own customer interface, you can integrate our investment APIs directly into your system. **Flow**: ``` Your System (Customer Interface) ↓ Create Wallet & Fund (via API) ↓ Get Quote & Submit Application (via API) ↓ Our System (Processing & Portfolio Creation) ↓ Your System (Receive Updates via Webhooks) ↓ Portfolio Created / Investment Active ``` **What You Handle**: * Customer interface and experience * Product selection and display * Application data collection * Portfolio display and notifications **What We Handle**: * Wallet management * Investment processing * Interest calculation * Portfolio tracking * Interest accrual All investment operations are accessible via our REST APIs. See the [API Reference](/api/investment/create-investment-application) for details. ## Next Steps Understand the complete investment account opening process Learn how to manage and track investment portfolios Explore investment performance metrics and analytics Jump into the API documentation and begin building # Portfolio management Source: https://docs.fincode.technology/investment/portfolio-management # Process Flow Source: https://docs.fincode.technology/investment/process-flow This guide details the complete customer journey for investment management, from product selection to portfolio management and returns. The flow covers **Product Selection**, **Quote**, **Investment Application**, **Wallet Creation**, **Funding**, and **Portfolio Management**. ## Phase 1: Product Selection & Quote ### 3.1 Browse Products & Get Quote Customers explore available investment products and get quotes for specific unit purchases. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant QuoteService Customer->>App: View Products Note right of Customer: Browse available investment products Customer->>App: Select Product & Units App->>API: GET /quote/get-quote/{product-id}/{units} API->>QuoteService: Calculate Quote QuoteService-->>API: Return Quote Details API-->>App: Quote with Fees & Total App-->>Customer: Display Quote ``` Get investment quote for units #### Quote Process Steps Customer browses and selects an investment product (Fixed Deposit, Mutual Fund, etc.). Customer specifies the number of units they want to purchase. System calculates and returns: * **Total Amount** (including fees) * **Fees Breakdown** * **Investing Amount** * **Per Unit Price** Customer reviews the quote and decides whether to proceed with the investment. ## Phase 2: Investment Application ### 4.1 Submit Investment Application Customers submit investment applications with product and unit details. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant InvestmentService Customer->>App: Submit Application App->>API: POST /apply API->>InvestmentService: Process Application InvestmentService->>InvestmentService: Validate Wallet Balance InvestmentService->>InvestmentService: Create Portfolio InvestmentService->>InvestmentService: Debit Wallet InvestmentService-->>API: Portfolio Created API-->>App: Application Confirmed App-->>Customer: Investment Active ``` Submit investment application #### Application Steps Customer provides: * **Investment Product ID** * **Number of Units to Purchase** * **Customer ID** * **Customer Name** * **Wallet ID** (source of funds) System validates: * Wallet has sufficient balance * Product is available * Customer is eligible System creates investment portfolio and: * Debits wallet with investment amount * Creates portfolio record * Sets up interest accrual * Records investment details Customer receives confirmation with portfolio ID and investment details. ## Phase 3: Wallet Creation & Funding ### 3.1 Automatic Wallet Creation When an investment application is submitted, a wallet account is automatically created for the customer. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant InvestmentService participant WalletService Customer->>App: Submit Investment Application App->>API: POST /apply API->>InvestmentService: Process Application InvestmentService->>WalletService: Create Wallet Automatically WalletService->>WalletService: Generate Account Number WalletService->>WalletService: Create Wallet Record WalletService-->>InvestmentService: Wallet Created InvestmentService-->>API: Wallet Ready API-->>App: Application Received App-->>Customer: Wallet Created ``` The wallet is automatically created in the currency of the investment product. No customer action is required for wallet creation. ### 3.2 Fund Wallet After the wallet is created, customers fund it to cover the investment amount. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant WalletService Customer->>App: Fund Wallet Request App->>API: PUT /wallet/fund-wallet/{wallet-id}/{amount} API->>WalletService: Process Funding WalletService->>WalletService: Validate Wallet WalletService->>WalletService: Credit Wallet WalletService->>WalletService: Update Balance WalletService-->>API: Funding Confirmed API-->>App: Return Success App-->>Customer: Balance Updated ``` Add funds to investment wallet #### Funding Steps Wallet is automatically created when investment application is submitted. Customer adds funds to the wallet to cover the investment amount (including fees). Once wallet is funded, the investment is processed and portfolio is created. ## Phase 4: Portfolio Management ### 5.1 View Portfolios & Track Performance Customers can view all their investment portfolios and track performance. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant PortfolioService Customer->>App: View Portfolios App->>API: GET /portfolios/{customer-id} API->>PortfolioService: Fetch Portfolios PortfolioService-->>API: Return Portfolio List API-->>App: Portfolio Details App-->>Customer: Display Portfolios Customer->>App: View Dashboard App->>API: GET /get-total/{user-id} API->>PortfolioService: Calculate Totals PortfolioService-->>API: Total Investments & Interest API-->>App: Dashboard Data App-->>Customer: Display Summary ``` View all investment portfolios View dashboard summary #### Portfolio Management Steps Customer can view all their investment portfolios with details: * **Investment Amount** * **Total Payable** * **APY (Annual Percentage Yield)** * **Product Information** * **Request Date & Due Date** * **Maturity Information** Customer can view: * **Total Investments** across all products * **Total Interest Accrued** * **Individual Portfolio Performance** * **Maturity Dates** System automatically: * Calculates and accrues interest * Updates portfolio balances * Tracks maturity dates * Provides performance metrics ## Complete Investment Flow ```mermaid theme={null} flowchart TD A[Start] --> B{Browse Products} B --> C[Get Quote] C --> D{Review Quote} D -->|Proceed| E[Submit Application] D -->|Cancel| B E --> F[Wallet Created Automatically] F --> G[Fund Wallet] G --> H{Validation} H -->|Success| I[Portfolio Created] H -->|Insufficient Funds| G I --> J[Track Portfolio] J --> K[Monitor Returns] K --> L[View Dashboard] L --> M[End] ``` ## Key Concepts ### Investment Products * **Fixed Investments**: Corporate bonds with fixed terms and returns * **Dynamic Investments**: Mutual funds with variable returns * **Risk Profiles**: Conservative, Moderate, and Aggressive options * **Unit-Based**: Investments made in units with per-unit pricing ### Interest Accrual * **APY-Based**: Interest calculated using Annual Percentage Yield * **Automatic**: Interest accrues automatically based on product terms * **Real-Time**: Interest tracked and updated in real-time * **Currency-Specific**: Interest tracked per currency ### Portfolio Tracking * **Multiple Portfolios**: Customers can have multiple investment portfolios * **Performance Metrics**: Track investments, returns, and maturity * **Dashboard View**: Consolidated view of all investments * **Real-Time Updates**: Portfolio data updated automatically Explore detailed portfolio management features. See all available investment API endpoints. # Trading Flow Source: https://docs.fincode.technology/investment/trading-flow This guide details the trading and investment execution flow, from quote generation to portfolio creation and interest accrual. The trading flow covers **Quote Generation**, **Application Submission**, **Execution**, **Portfolio Creation**, and **Interest Accrual**. ## Trading Flow Overview The investment trading flow enables customers to execute investments seamlessly through a quote-based system that provides transparency and real-time pricing. ```mermaid theme={null} flowchart LR A[Get Quote] --> B[Review Quote] B --> C[Submit Application] C --> D[Validate & Execute] D --> E[Create Portfolio] E --> F[Start Interest Accrual] F --> G[Track Performance] ``` ## Phase 1: Quote Generation ### 1.1 Request Investment Quote Customers request quotes for specific investment products and unit quantities. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant QuoteService participant ProductService Customer->>App: Select Product & Units App->>API: GET /quote/get-quote/{product-id}/{units} API->>ProductService: Get Product Details ProductService-->>API: Product Information API->>QuoteService: Calculate Quote QuoteService->>QuoteService: Calculate Fees QuoteService->>QuoteService: Calculate Total QuoteService-->>API: Quote Details API-->>App: Return Quote App-->>Customer: Display Quote ``` Get real-time investment quote ### Quote Components The quote includes: * **Product Information**: Product name, type, and details * **Unit Price**: Price per unit of the investment * **Number of Units**: Quantity requested * **Fees**: Applicable fees for the investment * **Total Amount**: Total cost including fees * **Investing Amount**: Net amount to be invested Quotes are calculated in real-time based on current product pricing and fee structures. Quote validity may vary by product. ## Phase 2: Application Submission ### 2.1 Submit Investment Application After reviewing the quote, customers submit their investment application. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant InvestmentService participant WalletService Customer->>App: Confirm Investment App->>API: POST /apply API->>InvestmentService: Process Application InvestmentService->>InvestmentService: Validate Application InvestmentService->>WalletService: Create Wallet Automatically WalletService->>WalletService: Generate Account Number WalletService-->>InvestmentService: Wallet Created InvestmentService-->>API: Application Received API-->>App: Wallet Created App-->>Customer: Fund Wallet Required ``` Submit investment application ### Application Validation The system validates: 1. **Product Availability**: Product is active and available 2. **Unit Quantity**: Valid number of units requested 3. **Customer Eligibility**: Customer meets product requirements 4. **Quote Accuracy**: Application matches recent quote After validation, a wallet is automatically created for the customer. The customer then needs to fund the wallet to complete the investment. If wallet balance is insufficient, the application will be rejected. Ensure the wallet is funded before submitting the application. ## Phase 3: Wallet Funding & Execution ### 3.1 Fund Wallet After the wallet is automatically created, the customer funds it to complete the investment. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant WalletService participant InvestmentService participant PortfolioService participant InterestService Customer->>App: Fund Wallet App->>API: PUT /wallet/fund-wallet/{wallet-id}/{amount} API->>WalletService: Process Funding WalletService->>WalletService: Credit Wallet WalletService-->>API: Funding Confirmed API->>InvestmentService: Process Investment InvestmentService->>WalletService: Debit Wallet WalletService->>WalletService: Process Debit WalletService-->>InvestmentService: Debit Confirmed InvestmentService->>PortfolioService: Create Portfolio PortfolioService->>PortfolioService: Record Investment Details PortfolioService->>PortfolioService: Set Maturity Date PortfolioService-->>InvestmentService: Portfolio Created InvestmentService->>InterestService: Initialize Interest Accrual InterestService-->>InvestmentService: Accrual Started InvestmentService-->>API: Investment Complete API-->>App: Portfolio Created App-->>Customer: Investment Active ``` ### Execution Steps A wallet account is automatically created when the investment application is submitted. Customer funds the wallet with the investment amount (including fees). System debits the investment amount (including fees) from the customer's wallet. System creates a portfolio entry with: * Investment amount * Number of units * Product details * APY (Annual Percentage Yield) * Request date * Maturity date * Total payable System sets up automatic interest calculation and accrual based on product APY. Customer receives confirmation with portfolio ID and investment details. ## Phase 4: Interest Accrual ### 4.1 Automatic Interest Calculation The system automatically calculates and accrues interest based on product terms. ```mermaid theme={null} sequenceDiagram participant InterestService participant PortfolioService participant Database loop Daily/Periodic Accrual InterestService->>PortfolioService: Get Active Portfolios PortfolioService-->>InterestService: Portfolio List InterestService->>InterestService: Calculate Interest InterestService->>InterestService: Apply APY Formula InterestService->>Database: Update Accrued Interest Database-->>InterestService: Updated end ``` ### Interest Calculation Interest accrual follows these principles: * **APY-Based**: Uses Annual Percentage Yield for calculation * **Automatic**: Accrues automatically based on product terms * **Periodic**: Calculated at defined intervals (daily, monthly, etc.) * **Compounding**: May compound based on product configuration * **Currency-Specific**: Tracked per currency Interest accrual is automatic and requires no customer action. Customers can view accrued interest through the dashboard or portfolio details. ## Phase 5: Performance Tracking ### 5.1 Monitor Investment Performance Customers can track their investment performance through portfolios and dashboard. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant PortfolioService participant InterestService Customer->>App: View Portfolios App->>API: GET /portfolios/{customer-id} API->>PortfolioService: Fetch Portfolios PortfolioService->>InterestService: Get Accrued Interest InterestService-->>PortfolioService: Interest Data PortfolioService-->>API: Portfolio with Interest API-->>App: Return Data App-->>Customer: Display Performance Customer->>App: View Dashboard App->>API: GET /get-total/{user-id} API->>PortfolioService: Calculate Totals PortfolioService-->>API: Total Investments API->>InterestService: Get Total Interest InterestService-->>API: Total Interest Accrued API-->>App: Dashboard Summary App-->>Customer: Display Summary ``` View investment portfolios View dashboard summary ### Performance Metrics Customers can track: * **Investment Amount**: Original amount invested * **Accrued Interest**: Total interest earned to date * **Total Payable**: Total amount including principal and interest * **APY**: Annual Percentage Yield of the investment * **Maturity Date**: When the investment matures * **Performance**: Return on investment percentage ## Complete Trading Flow Diagram ```mermaid theme={null} flowchart TD Start([Customer Ready to Invest]) --> GetQuote[Get Quote] GetQuote --> ReviewQuote{Review Quote} ReviewQuote -->|Accept| SubmitApp[Submit Application] ReviewQuote -->|Reject| GetQuote SubmitApp --> Validate{Validate Application} Validate -->|Valid| CreateWallet[Create Wallet Automatically] Validate -->|Invalid| Error[Return Error] CreateWallet --> FundWallet[Fund Wallet] FundWallet --> CheckBalance{Wallet Balance
Sufficient?} CheckBalance -->|Yes| DebitWallet[Debit Wallet] CheckBalance -->|No| FundWallet DebitWallet --> CreatePortfolio[Create Portfolio] CreatePortfolio --> StartAccrual[Start Interest Accrual] StartAccrual --> Confirm[Send Confirmation] Confirm --> Track[Track Performance] Track --> End([Investment Active]) Error --> GetQuote ``` ## Key Trading Concepts ### Quote Validity * Quotes are calculated in real-time * Quote prices may change based on market conditions * Customers should submit applications promptly after receiving quotes * System validates quote accuracy during application processing ### Execution Timing * Applications are processed immediately upon submission * Portfolio creation happens synchronously * Interest accrual begins immediately after portfolio creation * No manual approval required for standard investments ### Fee Structure * Fees are included in the quote * Fees are deducted from wallet along with investment amount * Fee structure varies by product type * Total amount includes all applicable fees Explore portfolio management and tracking features. See the complete investment process flow. # Withdrawal Process Source: https://docs.fincode.technology/investment/withdrawal-process This guide details the process for withdrawing funds from investment portfolios, including maturity withdrawals and early withdrawal options. The withdrawal process covers **Maturity Withdrawals**, **Early Withdrawals**, **Fund Transfer**, and **Portfolio Closure**. ## Withdrawal Overview Investment withdrawals allow customers to access their invested funds and accrued interest. The process varies based on investment type, maturity status, and product terms. ```mermaid theme={null} flowchart LR A[Investment Matures] --> B[Withdrawal Available] B --> C[Request Withdrawal] C --> D[Process Withdrawal] D --> E[Funds to Wallet] E --> F[Portfolio Closed] ``` ## Phase 1: Maturity Withdrawal ### 1.1 Automatic Maturity Processing When an investment reaches maturity, funds become available for withdrawal. ```mermaid theme={null} sequenceDiagram participant System participant PortfolioService participant InterestService participant WalletService System->>PortfolioService: Check Maturity Dates PortfolioService->>PortfolioService: Identify Matured Investments PortfolioService->>InterestService: Calculate Final Interest InterestService-->>PortfolioService: Final Interest Amount PortfolioService->>PortfolioService: Calculate Total Payable PortfolioService->>WalletService: Credit Wallet WalletService->>WalletService: Process Credit WalletService-->>PortfolioService: Credit Confirmed PortfolioService->>PortfolioService: Close Portfolio PortfolioService-->>System: Withdrawal Complete ``` ### Maturity Withdrawal Steps System automatically detects when investments reach their maturity date. System calculates: * **Principal Amount**: Original investment * **Accrued Interest**: Total interest earned * **Total Payable**: Principal + Interest System automatically credits the customer's wallet with the total payable amount. Portfolio is marked as closed and moved to investment history. For fixed-term investments, funds are automatically credited to the wallet upon maturity. No customer action is required. ## Phase 2: Early Withdrawal ### 2.1 Request Early Withdrawal Some investment products may allow early withdrawal before maturity, subject to terms and conditions. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant PortfolioService participant ProductService participant WalletService Customer->>App: Request Early Withdrawal App->>API: POST /withdraw/{portfolio-id} API->>ProductService: Check Product Terms ProductService-->>API: Withdrawal Allowed API->>PortfolioService: Process Withdrawal PortfolioService->>PortfolioService: Calculate Early Withdrawal Amount PortfolioService->>PortfolioService: Apply Penalties (if any) PortfolioService->>WalletService: Credit Wallet WalletService-->>PortfolioService: Credit Confirmed PortfolioService->>PortfolioService: Close Portfolio PortfolioService-->>API: Withdrawal Processed API-->>App: Withdrawal Confirmed App-->>Customer: Funds Available ``` Early withdrawals may be subject to penalties or reduced interest rates depending on the product terms. Always review product terms before requesting early withdrawal. ### Early Withdrawal Considerations * **Product Terms**: Check if early withdrawal is allowed * **Penalties**: May incur penalties or forfeit interest * **Processing Time**: May take longer than maturity withdrawals * **Partial Withdrawal**: Some products may allow partial withdrawals ## Phase 3: Withdrawal to Wallet ### 3.1 Fund Transfer Process Withdrawn funds are credited to the customer's investment wallet. ```mermaid theme={null} sequenceDiagram participant PortfolioService participant WalletService participant Customer PortfolioService->>WalletService: Credit Request WalletService->>WalletService: Validate Wallet WalletService->>WalletService: Process Credit WalletService->>WalletService: Update Balance WalletService-->>PortfolioService: Credit Confirmed PortfolioService->>Customer: Notification Sent ``` ### Wallet Credit Details * **Automatic Credit**: Funds are automatically credited to the investment wallet * **Balance Update**: Wallet balance is updated immediately * **Transaction Record**: Withdrawal transaction is recorded * **Notification**: Customer receives confirmation notification Withdrawn funds are credited to the same wallet used for the investment. Customers can then transfer funds from the wallet to their bank account if needed. ## Phase 4: Portfolio Closure ### 4.1 Close Investment Portfolio After withdrawal, the portfolio is closed and moved to investment history. ```mermaid theme={null} flowchart TD A[Withdrawal Processed] --> B[Update Portfolio Status] B --> C[Mark as Closed] C --> D[Move to History] D --> E[Archive Records] E --> F[Portfolio Closed] ``` ### Portfolio Closure Steps Portfolio status is updated to "CLOSED" or "WITHDRAWN". System records: * Final withdrawal amount * Total interest earned * Investment duration * Withdrawal date Portfolio is moved to investment history for record-keeping. Customer dashboard is updated to reflect closed portfolio. ## Withdrawal Types ### Automatic Maturity Withdrawal * **Trigger**: Investment reaches maturity date * **Process**: Automatic, no customer action required * **Timing**: Processed on maturity date * **Amount**: Full principal + accrued interest ### Manual Early Withdrawal * **Trigger**: Customer request before maturity * **Process**: Requires customer action via API * **Timing**: Processed upon request * **Amount**: May be reduced by penalties ### Partial Withdrawal * **Availability**: Depends on product terms * **Process**: Customer specifies withdrawal amount * **Portfolio**: Remains active with reduced balance * **Interest**: Continues to accrue on remaining balance ## Withdrawal Flow Diagram ```mermaid theme={null} flowchart TD Start([Investment Active]) --> CheckMaturity{Maturity Reached?} CheckMaturity -->|Yes| AutoWithdraw[Automatic Withdrawal] CheckMaturity -->|No| CheckEarly{Early Withdrawal Request?} CheckEarly -->|Yes| ValidateEarly{Product Allows?} ValidateEarly -->|Yes| ProcessEarly[Process Early Withdrawal] ValidateEarly -->|No| Reject[Reject Request] ProcessEarly --> CalculateAmount[Calculate Withdrawal Amount] AutoWithdraw --> CalculateAmount CalculateAmount --> ApplyPenalties{Apply Penalties?} ApplyPenalties -->|Yes| ReduceAmount[Reduce Amount] ApplyPenalties -->|No| CreditWallet[Credit Wallet] ReduceAmount --> CreditWallet CreditWallet --> ClosePortfolio[Close Portfolio] ClosePortfolio --> UpdateHistory[Update History] UpdateHistory --> NotifyCustomer[Notify Customer] NotifyCustomer --> End([Withdrawal Complete]) Reject --> End ``` ## Key Concepts ### Maturity Date * **Fixed Term**: Investments have defined maturity dates * **Automatic Processing**: Matured investments are processed automatically * **No Action Required**: Customers don't need to request maturity withdrawals * **Full Amount**: Full principal and interest are paid at maturity ### Early Withdrawal Terms * **Product-Specific**: Terms vary by investment product * **Penalties**: May include penalties or reduced interest * **Processing**: May require manual review * **Availability**: Not all products allow early withdrawal ### Withdrawal Amount Calculation * **Principal**: Original investment amount * **Accrued Interest**: Interest earned to date * **Penalties**: Deducted for early withdrawals (if applicable) * **Total Payable**: Final amount credited to wallet Explore portfolio management and tracking. See the complete investment process flow. # Balance Management Source: https://docs.fincode.technology/ledger/balance-management Balance management is a critical aspect of the Ledger Engine, ensuring accurate tracking of account balances, available funds, and account status. ## Overview The Ledger Engine maintains multiple balance types for each account to provide accurate financial information: * **Account Balance**: Total balance including all transactions * **Available Balance**: Funds available for new transactions * **Lien Amount**: Funds frozen or held * **Overdraft Balance**: Amount of overdraft currently used ## Balance Types ### Account Balance The **account balance** represents the total balance of the account, including all debits and credits. ``` Account Balance = Sum of all Credits - Sum of all Debits ``` This is the primary balance that reflects the true financial position of the account. ### Available Balance The **available balance** is the amount that can be used for new transactions. It excludes: * **Lien Amount**: Funds placed on lien (frozen) * **Holds**: Temporary holds on funds * **Pending Debits**: Debits that are pending but not yet finalized ``` Available Balance = Account Balance - Lien Amount - Holds - Pending Debits ``` Available balance is what you should check before allowing new transactions to ensure sufficient funds. ### Lien Amount A **lien** is a legal claim or hold on funds in an account, making them unavailable for transactions. * Funds on lien cannot be debited * Lien can be placed by administrators * Lien can be released when conditions are met ### Overdraft Balance **Overdraft** allows accounts to have a negative balance up to a specified limit. * **Overdraft Limit**: Maximum negative balance allowed * **Used Overdraft**: Current amount of overdraft being used * **Available Overdraft**: Remaining overdraft capacity ``` Available Overdraft = Overdraft Limit - Used Overdraft Amount ``` ## Balance Calculation Flow ### Real-Time Updates Balances are updated in real-time with every transaction: ```mermaid theme={null} sequenceDiagram participant Transaction participant LedgerService participant Account Transaction->>LedgerService: Post Transaction LedgerService->>Account: Calculate New Balance Account->>Account: Update Account Balance Account->>Account: Recalculate Available Balance Account->>Account: Update Overdraft Balance (if applicable) Account-->>LedgerService: Balance Updated LedgerService-->>Transaction: Return Updated Balance ``` ### Balance Query Process When querying account balance: ```mermaid theme={null} flowchart TD A[Balance Query Request] --> B[Retrieve Account] B --> C[Get Account Balance] C --> D[Calculate Available Balance] D --> E[Get Lien Amount] E --> F[Get Overdraft Information] F --> G[Return Balance Details] ``` View the complete API documentation for balance queries. ## Balance Components ### Account Balance Response When querying an account balance, you receive: * **accountBalance**: Total account balance * **availableBalance**: Available funds for transactions * **totalLienAmount**: Total amount on lien * **overDraftLimit**: Maximum overdraft allowed * **newOverDraftBalance**: Current overdraft used * **accountStatus**: Current account status * **currencyCode**: Account currency ## Balance Updates ### After Debit Transaction When money is debited from an account: ``` Previous Account Balance: 10,000 NGN Debit Amount: 2,000 NGN New Account Balance: 8,000 NGN New Available Balance: 8,000 NGN (if no liens) ``` ### After Credit Transaction When money is credited to an account: ``` Previous Account Balance: 8,000 NGN Credit Amount: 5,000 NGN New Account Balance: 13,000 NGN New Available Balance: 13,000 NGN (if no liens) ``` ### With Lien When a lien is placed on funds: ``` Account Balance: 10,000 NGN Lien Amount: 3,000 NGN Available Balance: 7,000 NGN (10,000 - 3,000) ``` ### With Overdraft When account uses overdraft: ``` Account Balance: -2,000 NGN (negative) Overdraft Limit: 5,000 NGN Used Overdraft: 2,000 NGN Available Overdraft: 3,000 NGN (5,000 - 2,000) Available Balance: -2,000 NGN (can go more negative up to limit) ``` ## Balance Validation ### Before Transaction Before processing a debit transaction, the system validates: 1. **Account Status**: Account must be ACTIVATED 2. **Available Balance**: Must be sufficient (or overdraft available) 3. **Lien Check**: Account must not be fully on lien 4. **Currency Match**: Transaction currency must match account currency ### Insufficient Balance Handling When balance is insufficient: * Transaction is rejected * No balance changes occur * Error returned: `INSUFFICIENT_FUNDS` Always check available balance before attempting debit transactions. Account balance alone is not sufficient - you must check available balance. ## Balance Tracking ### Transaction History Every transaction records balance changes: * **previousAccountBalance**: Balance before transaction * **newBalance**: Balance after transaction * **transactionAmount**: Amount of the transaction View transaction history to track balance changes. ### Balance Reconciliation To reconcile account balances: 1. **Get Current Balance**: Query account balance 2. **Get Transaction History**: Retrieve all transactions 3. **Calculate Expected Balance**: Sum all credits and debits 4. **Compare**: Current balance should match calculated balance ## Multi-Currency Balances Each account maintains balances in a specific currency: * **Currency-Specific**: Each currency has its own balance * **No Cross-Currency**: Cannot debit NGN and credit USD in same transaction * **Separate Accounts**: Different currencies require separate accounts ## Best Practices ### 1. Always Check Available Balance Before debiting, always check available balance, not just account balance. ### 2. Handle Negative Balances If overdraft is allowed, handle negative balances appropriately. ### 3. Monitor Lien Amounts Be aware of lien amounts that reduce available balance. ### 4. Track Balance Changes Use transaction history to track how balances change over time. ### 5. Reconcile Regularly Periodically reconcile balances with transaction history. Query account balances with the API. Understand the complete balance query flow. # Double-Entry Posting Source: https://docs.fincode.technology/ledger/double-entry-posting Double-entry posting is the core mechanism of the Ledger Engine, ensuring every financial transaction is recorded accurately with both debit and credit entries. ## Overview Double-entry bookkeeping is a fundamental accounting principle where every transaction affects at least two accounts: * **Debit Entry**: Records money leaving an account * **Credit Entry**: Records money entering an account * **Balance**: Total debits must equal total credits This ensures the accounting equation always balances: Assets = Liabilities + Equity ## How Double-Entry Works ### Basic Principle Every transaction creates two equal and opposite entries: ```mermaid theme={null} flowchart LR A[Transaction] --> B[Debit Entry] A --> C[Credit Entry] B --> D[Account Balance Decreases] C --> E[Account Balance Increases] D --> F[Total Debits = Total Credits] E --> F ``` ### Example: Transfer Between Accounts When transferring 1000 NGN from Account A to Account B: 1. **Debit Account A**: 1000 NGN (money leaving) 2. **Credit Account B**: 1000 NGN (money entering) Both entries are recorded simultaneously, ensuring the books always balance. ## Transaction Posting Flow ### Step 1: Prepare Transaction Before posting, you need: * **Primary Account**: The main account involved * **Counterparty Account(s)**: One or more accounts to credit/debit * **Amount**: Transaction amount * **Direction**: Whether to debit or credit the primary account * **Currency**: Transaction currency (must match account currencies) * **Idempotency Key**: Unique key to prevent duplicates ### Step 2: Validate Accounts The system validates: ```mermaid theme={null} flowchart TD A[Validate Accounts] --> B{Account Exists?} B -->|No| C[Return Error: Account Not Found] B -->|Yes| D{Account Active?} D -->|No| E[Return Error: Account Deactivated] D -->|Yes| F{Currency Match?} F -->|No| G[Return Error: Currency Mismatch] F -->|Yes| H{Has Permission?} H -->|No| I[Return Error: Transaction Not Permitted] H -->|Yes| J[Accounts Valid] ``` View the complete API documentation for posting transactions. ### Step 3: Lock Accounts To prevent concurrent modifications: * System locks all accounts involved in the transaction * Uses pessimistic locking to ensure data integrity * Locks are released after transaction completion ### Step 4: Check Balance For debit transactions, the system checks: * **Available Balance**: Sufficient funds available * **Lien Amount**: Account is not frozen * **Overdraft**: If overdraft is allowed and within limits ```mermaid theme={null} sequenceDiagram participant System participant AccountService System->>AccountService: Check Available Balance AccountService->>AccountService: Calculate Available Balance AccountService->>AccountService: Check Lien Amount AccountService->>AccountService: Check Overdraft Status AccountService-->>System: Balance Status System->>System: Validate Sufficient Funds ``` ### Step 5: Create Ledger Entries The system creates ledger entries: 1. **Debit Entry**: * Records money leaving the primary account * Updates account balance (decreases) * Records transaction details 2. **Credit Entry**: * Records money entering counterparty account(s) * Updates account balance (increases) * Records transaction details ```mermaid theme={null} sequenceDiagram participant System participant LedgerService participant AccountA participant AccountB System->>LedgerService: Create Debit Entry LedgerService->>AccountA: Debit Amount AccountA->>AccountA: Update Balance AccountA-->>LedgerService: Balance Updated System->>LedgerService: Create Credit Entry LedgerService->>AccountB: Credit Amount AccountB->>AccountB: Update Balance AccountB-->>LedgerService: Balance Updated LedgerService-->>System: Transaction Complete ``` ### Step 6: Update Balances Account balances are updated atomically: * **Primary Account**: Balance decreased (for debits) or increased (for credits) * **Counterparty Account(s)**: Balance increased (for credits) or decreased (for debits) * **Available Balance**: Recalculated excluding liens and holds ### Step 7: Record Transaction The transaction is recorded in the ledger with: * Transaction ID * Account IDs * Amount and currency * Previous and new balances * Execution date * Correlation IDs (internal and external) * Idempotency key * Payment reference ## Transaction Directions ### Debit Primary, Credit Counterparty Use this when money flows **from** the primary account **to** counterparty accounts. **Example**: Customer pays 5000 NGN from their wallet to a merchant account. * Debit: Customer Wallet (5000 NGN) * Credit: Merchant Account (5000 NGN) ### Credit Primary, Debit Counterparty Use this when money flows **to** the primary account **from** counterparty accounts. **Example**: Customer receives 10000 NGN from a loan disbursement. * Credit: Customer Wallet (10000 NGN) * Debit: Loan Disbursement Account (10000 NGN) ## Multiple Counterparties A single transaction can involve multiple counterparty accounts: **Example**: Split payment to multiple recipients * Debit: Primary Account (15000 NGN) * Credit: Counterparty A (5000 NGN) * Credit: Counterparty B (5000 NGN) * Credit: Counterparty C (5000 NGN) Total debits (15000) = Total credits (15000) ## Idempotency Every transaction requires an idempotency key: * **Prevents Duplicates**: Same key cannot be used twice * **Idempotent Requests**: Re-submitting with same key returns original result * **Transaction Tracking**: Key links all related ledger entries Always use unique idempotency keys for each transaction. Reusing a key will return the original transaction result, not create a new one. ## Error Handling ### Insufficient Funds If available balance is insufficient: * Transaction is rejected * No ledger entries are created * Account balances remain unchanged * Error response: `INSUFFICIENT_FUNDS` ### Account Not Found If account doesn't exist: * Transaction is rejected * Error response: `ACCOUNT_NOT_FOUND` ### Account Deactivated If account is not active: * Transaction is rejected * Error response: `ACCOUNT_DEACTIVATED` ### Transaction Not Permitted If account permissions don't allow the transaction: * Transaction is rejected * Error response: `TRANSACTION_NOT_PERMITTED` ## Transaction States After posting, transactions have the following states: * **PAID**: Transaction successful, balances updated * **FAILED**: Transaction failed, no changes made * **PENDING**: Transaction being processed (rare for ledger operations) ## Best Practices ### 1. Always Use Idempotency Keys Generate unique idempotency keys for each transaction to prevent duplicates. ### 2. Validate Before Posting Check account balances and status before attempting to post transactions. ### 3. Handle Errors Gracefully Implement proper error handling for all possible failure scenarios. ### 4. Track Correlation IDs Use correlation IDs to track related transactions across systems. ### 5. Verify Balances After posting, verify account balances to ensure transaction was successful. See the complete API documentation with examples. Understand the complete ledger process flow. # Overview Source: https://docs.fincode.technology/ledger/overview At Fincode, we have built a **modular, auditable ledger engine** that serves as the financial backbone for fintech companies to rapidly design, launch, and scale regulated financial products. Our ledger abstracts complexity around money movement, balances, interest, repayments, and reconciliations—allowing fintechs to focus on customer experience, distribution, and growth rather than core financial plumbing. ### What the Fincode Ledger Engine Does The Fincode ledger engine is a **real-time, double-entry accounting system** purpose-built for modern fintech use cases. It ensures accuracy, consistency, and regulatory alignment across all financial products. #### Core Capabilities * **Real-time balance management** * **Double-entry accounting** with immutable transaction records * **Multi-currency and multi-wallet support** * **Event-driven transaction posting** * **Product-level and customer-level segregation of funds** * **Full auditability and reconciliation readiness** ### How It Works The ledger engine flow consists of three main operations: Query account balances to get real-time available balance, account balance, and account details. Execute double-entry transactions by debiting one account and crediting another account with automatic balance updates. Retrieve complete transaction history for accounts with pagination support and filtering by interaction ID or idempotency key. For detailed visual flow, see the [Process Flow](/ledger/process-flow) page. ### Products You Can Build on the Ledger The ledger is product-agnostic and can be configured to support multiple fintech verticals: * Customer wallets (individual, business, escrow) * Available vs. ledger balance separation * Holds, reversals, fees, and settlements * Multi-currency and FX-ready structures * Loan principal, interest, fees, penalties * Amortisation schedules and repayment tracking * Partial repayments and restructures * NPL tracking and write-offs * Integration-ready for credit decisioning engines * Interest-bearing accounts * Fixed and flexible savings plans * Interest accrual and posting logic * Goal-based and pooled savings structures * Virtual investment accounts * Unitised balances and NAV tracking * Contributions, redemptions, and returns * Ledger-backed investor reporting and reconciliation ### Why the Ledger Matters Most fintech failures occur not at the UI layer, but at the ledger and reconciliation layer. Fincode’s approach ensures: * **Regulatory confidence** for EMI, MFB, bank, and PSP partners * **Scalability** from MVP to millions of transactions * **Audit-readiness** for regulators, banks, and investors * **Product velocity**, enabling faster launches and iterations ### How Fintechs Use Fincode Ledger Fincode’s ledger engine is typically used by: * **Fintech startups** launching wallets, lending, or savings products * **Banks and EMIs** offering Banking-as-a-Service or Lending-as-a-Service * **Embedded finance providers** building financial products into non-financial platforms * **Regulated institutions** modernising legacy core systems ### Integration Quick Start Before you begin: Contact our team to receive your sandbox API keys and base URL. Familiarize yourself with our [Ledger Engine API Reference](/api/ledger/account-balance). Read through the [Process Flow](/ledger/process-flow) to understand how transactions are processed. Explore all available ledger endpoints with request/response examples. ### Testing & Sandbox We provide a full-featured sandbox environment for testing: * **Sandbox URL**: `https://{domain}.fincode.software` * **Test credentials**: Provided upon registration * **Mock transactions**: Simulate account operations * **No real money**: All transactions are simulated Use the sandbox to test all flows, edge cases, and error handling before going live. ## Next Steps Visualize the complete ledger transaction flow with detailed diagrams Jump into the API documentation and begin building # Process Flow Source: https://docs.fincode.technology/ledger/process-flow This guide details the complete flow for ledger operations, from account balance queries to transaction posting and history retrieval. The flow covers **Account Balance Queries**, **Transaction Posting**, and **Ledger History Retrieval**. ## Phase 1: Account Balance Query ### 1.1 Get Account Balance Customers can query their account balance to get real-time balance information. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant LedgerService Customer->>App: Request Account Balance App->>API: GET /ledger/account-balance/{account_id} API->>LedgerService: Query Account Balance LedgerService->>LedgerService: Get Account Details LedgerService->>LedgerService: Calculate Balances LedgerService-->>API: Return Balance Details API-->>App: Balance Information App-->>Customer: Display Balance ``` Get account balance and details #### Balance Query Steps Customer requests balance for a specific account using the account ID. System retrieves account details including: * **Available Balance**: Funds available for transactions * **Account Balance**: Total account balance * **Account Status**: Current account status * **Currency**: Account currency * **Account Information**: Account number, name, and owner details System returns comprehensive balance information including overdraft limits and lien amounts if applicable. ## Phase 2: Transaction Posting ### 2.1 Post to Account Customers can execute double-entry transactions by posting debits and credits to accounts. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant LedgerService participant AccountService Customer->>App: Post Transaction Request App->>API: POST /gateway/post-account API->>LedgerService: Process Posting LedgerService->>AccountService: Validate Accounts AccountService-->>LedgerService: Accounts Valid LedgerService->>LedgerService: Lock Accounts LedgerService->>LedgerService: Check Balance LedgerService->>LedgerService: Create Debit Entry LedgerService->>LedgerService: Create Credit Entry LedgerService->>LedgerService: Update Balances LedgerService-->>API: Posting Complete API-->>App: Transaction Confirmed App-->>Customer: Transaction Success ``` Execute double-entry transaction #### Posting Steps Customer prepares transaction details: * **Primary Account**: Source or destination account * **Counterparty Accounts**: Accounts to credit or debit * **Amount**: Transaction amount * **Direction**: Debit or credit direction * **Narration**: Transaction description System validates: * Account existence * Account status (must be ACTIVATED) * Account permissions * Currency matching For debit transactions, system checks: * Available balance is sufficient * Account is not on lien (if applicable) * Overdraft limits (if applicable) System executes double-entry posting: * Creates debit entry in primary account * Creates credit entry in counterparty account(s) * Updates account balances * Records transaction in ledger Customer receives confirmation with transaction details and updated balances. ## Phase 3: Transaction History ### 3.1 Retrieve Ledger History Customers can retrieve complete transaction history for their accounts. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant LedgerService Customer->>App: Request Transaction History App->>API: GET /ledger/account-ledger-history/{account_id}/{page}/{size} API->>LedgerService: Query Ledger History LedgerService->>LedgerService: Retrieve Transactions LedgerService->>LedgerService: Apply Pagination LedgerService-->>API: Return History API-->>App: Transaction List App-->>Customer: Display History ``` View account transaction history View transactions by interaction ID View transactions by idempotency key #### History Retrieval Steps Customer requests transaction history for an account with pagination parameters. System retrieves ledger entries including: * Transaction amount and type * Previous and new balances * Execution date * Payment reference * Correlation IDs System applies pagination and returns the requested page of transactions. Customer views complete transaction history with all details. ## Complete Ledger Flow ```mermaid theme={null} flowchart TD Start([Start]) --> QueryBalance{Query Balance?} QueryBalance -->|Yes| GetBalance[Get Account Balance] GetBalance --> DisplayBalance[Display Balance] DisplayBalance --> End1([End]) QueryBalance -->|No| PostTransaction{Post Transaction?} PostTransaction -->|Yes| Validate[Validate Accounts] Validate --> CheckBalance{Balance
Sufficient?} CheckBalance -->|Yes| Execute[Execute Transaction] CheckBalance -->|No| Error1[Return Error] Execute --> UpdateBalances[Update Balances] UpdateBalances --> RecordLedger[Record in Ledger] RecordLedger --> Confirm[Send Confirmation] Confirm --> End2([End]) Error1 --> End2 PostTransaction -->|No| GetHistory{Get History?} GetHistory -->|Yes| RetrieveHistory[Retrieve Ledger History] RetrieveHistory --> ApplyPagination[Apply Pagination] ApplyPagination --> DisplayHistory[Display History] DisplayHistory --> End3([End]) GetHistory -->|No| End4([End]) ``` ## Key Concepts ### Double-Entry Posting Every transaction creates two entries: * **Debit Entry**: Money leaving an account * **Credit Entry**: Money entering an account * Both entries must balance (total debits = total credits) ### Account Balances * **Account Balance**: Total balance including all transactions * **Available Balance**: Balance available for new transactions (excludes liens and holds) * **Overdraft Balance**: Amount of overdraft currently used (if applicable) * **Lien Amount**: Amount placed on lien (frozen/unavailable) ### Transaction Types * **DEBIT**: Money leaving the account * **CREDIT**: Money entering the account * **TRANSFER**: Money moving between accounts (debit one, credit another) ### Idempotency * Every transaction requires an idempotency key * Duplicate requests with the same idempotency key return the original transaction * Prevents accidental duplicate processing See all available ledger API endpoints. # Transaction History & Audit Source: https://docs.fincode.technology/ledger/transaction-history Transaction history provides a complete audit trail of all account movements, enabling reconciliation, reporting, and compliance. ## Overview The Ledger Engine maintains a complete, immutable record of all transactions: * **Complete Audit Trail**: Every transaction is recorded permanently * **Immutable Records**: Ledger entries cannot be modified or deleted * **Detailed Information**: Each entry includes amounts, dates, references, and correlation IDs * **Multiple Query Options**: Retrieve history by account, interaction ID, or idempotency key All ledger entries are immutable. Once recorded, they cannot be changed, ensuring data integrity and audit compliance. ## Ledger Entry Structure Each ledger entry contains: ### Transaction Details * **Transaction ID**: Unique identifier for the entry * **Transaction Amount**: Amount of the transaction * **Currency Code**: Transaction currency * **Ledger Type**: DEBIT or CREDIT * **Status**: Transaction status (PAID, FAILED, etc.) ### Balance Information * **Previous Account Balance**: Balance before this transaction * **New Balance**: Balance after this transaction * **Account ID**: Account involved in the transaction ### Tracking Information * **Idempotency Key**: Unique key used for the transaction * **External Correlation ID**: External system correlation ID (interaction ID) * **Internal Correlation ID**: Internal system correlation ID * **Posting Group ID**: Groups related transactions together ### Metadata * **Execution Date**: When the transaction was executed * **Payment Reference**: Payment or transaction reference * **Depositor Full Name**: Name of the person/entity initiating transaction * **Action Performed By User**: User who performed the action ## Querying Transaction History ### By Account Retrieve all transactions for a specific account with pagination: ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant LedgerService Customer->>App: Request Account History App->>API: GET /ledger/account-ledger-history/{account_id}/{page}/{size} API->>LedgerService: Query Ledger History LedgerService->>LedgerService: Retrieve Transactions LedgerService->>LedgerService: Apply Pagination LedgerService-->>API: Return History API-->>App: Transaction List App-->>Customer: Display History ``` View the complete API documentation for account history. ### By Interaction ID Retrieve all transactions related to a specific interaction or session: ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant LedgerService Customer->>App: Request by Interaction ID App->>API: GET /ledger/account-ledger-history-interaction-id Note over API: Uses x-fapi-interaction-id header API->>LedgerService: Query by External Correlation ID LedgerService->>LedgerService: Find Matching Transactions LedgerService-->>API: Return Transactions API-->>App: Transaction List App-->>Customer: Display Related Transactions ``` View the complete API documentation. ### By Idempotency Key Retrieve all transactions processed with a specific idempotency key: ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant LedgerService Customer->>App: Request by Idempotency Key App->>API: GET /ledger/account-ledger-history-idempotencykey Note over API: Uses x-idempotency-key header API->>LedgerService: Query by Idempotency Key LedgerService->>LedgerService: Find Matching Transactions LedgerService-->>API: Return Transactions API-->>App: Transaction List App-->>Customer: Display Transactions ``` View the complete API documentation. ## Transaction History Use Cases ### 1. Account Statement Generate account statements by retrieving all transactions for an account: * Filter by date range (if supported) * Paginate through large transaction lists * Display in chronological order ### 2. Transaction Reconciliation Reconcile transactions by: * Matching external system transactions with ledger entries * Using correlation IDs to link related transactions * Verifying balances match expected values ### 3. Audit Trail Maintain audit trail for compliance: * Track all account movements * Identify who performed each transaction * Verify transaction integrity ### 4. Dispute Resolution Resolve disputes by: * Retrieving transaction details * Verifying transaction amounts and dates * Checking correlation IDs and references ## Pagination Transaction history supports pagination for large datasets: * **Page Number**: Which page to retrieve * **Page Size**: Number of items per page * **Total Count**: Total number of transactions (if available) Use pagination to efficiently retrieve large transaction histories without loading all records at once. ## Transaction Filtering ### By Date Range While not directly supported by all endpoints, you can: * Retrieve paginated history * Filter results client-side by execution date * Use interaction ID or idempotency key for specific transactions ### By Transaction Type Filter by ledger type: * **DEBIT**: Money leaving the account * **CREDIT**: Money entering the account ### By Status Filter by transaction status: * **PAID**: Successful transactions * **FAILED**: Failed transactions * **PENDING**: Pending transactions ## Balance Verification ### Verify Current Balance Use transaction history to verify current balance: 1. Get current account balance 2. Retrieve all transactions 3. Calculate expected balance: `Initial Balance + Sum(Credits) - Sum(Debits)` 4. Compare with current balance ### Identify Discrepancies If balances don't match: * Review transaction history for missing entries * Check for failed transactions that weren't recorded * Verify all transactions were properly posted ## Correlation IDs ### External Correlation ID (Interaction ID) Links transactions to external systems or sessions: * Use same interaction ID for related transactions * Track all transactions in a single session * Reconcile with external system records ### Internal Correlation ID Internal system tracking: * Links related transactions within the system * Groups transactions that are part of the same operation * Used for internal reconciliation ### Posting Group ID Groups transactions posted together: * Multiple transactions can share a posting group ID * Useful for batch operations * Helps identify related debit/credit pairs ## Best Practices ### 1. Use Pagination Always use pagination when retrieving large transaction histories. ### 2. Track Correlation IDs Store correlation IDs to enable transaction tracking and reconciliation. ### 3. Regular Reconciliation Periodically reconcile balances with transaction history. ### 4. Monitor Transaction Status Track transaction status to identify failed or pending transactions. ### 5. Archive Old Transactions For compliance, archive old transaction history as needed. View all transaction history endpoints. Understand how transaction history fits into the complete flow. # Disbursement & Withdrawal Source: https://docs.fincode.technology/lending/disbursement Disbursement is the final stage of the loan origination process where funds are released to the customer. Our platform utilizes a wallet-based disbursement model to ensure speed and control. ## The Disbursement Process Once a customer accepts a loan offer, the application is queued for disbursement. ### 1. Wallet Creation Upon the admin triggering disbursement: * The system automatically creates a **virtual wallet account** for the customer if one does not already exist. * This wallet serves as the destination for the loan proceeds. ### 2. Fund Crediting * The approved loan amount is credited to the customer's wallet. * The loan status changes to `DISBURSED`. * The repayment schedule is activated. Customers can view their total approved/disbursed loan amount. ## Withdrawal Process Customers cannot spend directly from the loan wallet; they must withdraw the funds to their personal bank account. ### Step 1: Add Bank Account The customer must link a valid bank account to their profile. 1. **Select Bank**: Choose from a list of supported banks. 2. **Enter Account Number**: Input the 10-digit NUBAN. 3. **Verification**: The system verifies the account name against the customer's profile name to prevent fraud. List supported banks Verify account details ### Step 2: Initiate Withdrawal The customer initiates a transfer from their wallet to their verified bank account. * **Source**: Disbursed Loan Wallet. * **Destination**: Verified Bank Account. * **Amount**: Any amount up to the available balance. **Withdrawal Fee**: A processing fee (e.g., 10 Naira) is automatically deducted from the withdrawal amount or the remaining wallet balance. ### Step 3: Processing The transfer is processed via our payment partners (e.g., Remita). * **Instant**: Most transfers are instant. * **Status Tracking**: Customers can track the status of their transfer. View the history and status of withdrawal transfers. ## Post-Disbursement After disbursement, the focus shifts to repayment. The system will automatically track due dates and can initiate auto-debits if configured. Customers can view their active loans and repayment schedules. # Loan Lifecycle Source: https://docs.fincode.technology/lending/loan-lifecycle Understanding the lifecycle of a loan application is crucial for integrating with the lending platform. This page details the various states a loan application can traverse and the triggers for each transition. ## State Diagram The following diagram illustrates the standard flow of a loan application from creation to disbursement. ```mermaid theme={null} stateDiagram-v2 [*] --> REQUESTED state "Processing" as Processing { REQUESTED --> APPROVED: Admin/System Approval REQUESTED --> REJECTED: Admin/System Rejection } state "Offer Phase" as Offer { APPROVED --> OFFER_SENT: Offer Generated OFFER_SENT --> ACCEPTED: Customer Accepts Offer OFFER_SENT --> REJECTED: Customer Rejects Offer } state "Fulfillment" as Fulfillment { ACCEPTED --> DISBURSED: Admin Disburses Funds } REJECTED --> [*] DISBURSED --> [*] note right of REQUESTED Initial state upon application submission end note note right of DISBURSED Funds credited to customer wallet end note ``` ## Loan States ### 1. REQUESTED The initial state when a customer submits a loan application. * **Trigger**: Customer calls `POST /request-loan`. * **Action Required**: Underwriting review (manual or automated). * **Next Possible States**: `APPROVED`, `REJECTED`. ### 2. APPROVED The application has passed underwriting checks and has been approved by a loan officer or the system. * **Trigger**: Admin approves the application via the dashboard or API. * **Context**: Loan terms (Amount, Rate, Tenure) are finalized in this state. * **Next Possible States**: `OFFER_SENT`. ### 3. OFFER\_SENT A formal loan offer has been generated and presented to the customer. * **Trigger**: System generates the offer after approval. * **Action Required**: Customer must review and accept/reject the offer. * **Next Possible States**: `ACCEPTED`, `REJECTED`. ### 4. ACCEPTED The customer has accepted the loan offer and agreed to the terms and conditions. * **Trigger**: Customer calls `PUT /accept-loan-offer/{id}/accept` and `PUT /accept-terms-and-conditions/{id}`. * **Action Required**: Admin disbursement. * **Next Possible States**: `DISBURSED`. ### 5. REJECTED The application was rejected by the system/admin, or the offer was rejected by the customer. * **Trigger**: * Admin/System rejects application (Credit risk, eligibility failure). * Customer calls `PUT /accept-loan-offer/{id}/reject`. * **Action Required**: None. This is a terminal state. ### 6. DISBURSED The loan funds have been successfully credited to the customer's wallet. * **Trigger**: Admin triggers disbursement. * **Context**: A wallet account is created, and the loan amount is credited. Repayment schedule is active. * **Next Possible States**: `COMPLETED` (after full repayment), `DEFAULTED` (if repayment fails). ## State Transitions & Webhooks You can subscribe to webhook events to receive real-time updates when a loan application changes state. | Event Name | Description | | :- | :- | | `loan.application.approved` | Triggered when status changes to APPROVED. | | `loan.offer.accepted` | Triggered when customer accepts the offer. | | `loan.disbursed` | Triggered when funds are disbursed. | | `loan.application.rejected` | Triggered when application is rejected. | Learn how to configure and handle webhook events. # Overview Source: https://docs.fincode.technology/lending/overview Welcome to the lending platform documentation. This guide will help you understand how our digital lending system works and how to integrate it into your application. ### What is Digital Lending? Our lending platform enables **fast, secure, and automated loan processing** for customers. The system supports: * **Loan Applications** - Customers can apply for loans through multiple channels * **Automated Underwriting** - Automated credit assessment and risk evaluation * **Fast Disbursement** - Funds are electronically disbursed to customer wallets * **Repayment Management** - Automated repayment tracking and collection ### Key Features Automated credit scoring and risk evaluation using credit bureaus, history and alternative data. Configure different loan products with varying interest rates, tenures, and eligibility criteria. Disburse loans to customer wallets or bank accounts. Track repayments, generate schedules, and manage collections automatically. Fast loan application processing with automated eligibility checks and instant decisions where applicable. RESTful APIs with comprehensive documentation and sandbox environment for seamless integration. ### How It Works The lending flow consists of five main phases: Customers apply for loans by selecting a product, providing required information, and answering eligibility questions. System processes the application, performs eligibility checks, and may trigger automated credit assessment. Loan officers can manually review applications, approve or reject based on risk assessment, and set loan terms. Approved loans are disbursed to a newly created customer wallet. Customers can then withdraw funds to their verified bank accounts. Customers make repayments according to schedule, with automated tracking and collection management. For detailed visual flow, see the [Process Flow](/lending/process-flow) and [Loan Lifecycle](/lending/loan-lifecycle) pages. ### Core Concepts #### Loan Application Lifecycle Every loan application moves through defined states from submission to completion: ``` REQUESTED → APPROVED → OFFER_SENT → ACCEPTED → DISBURSED ``` Applications can also transition to `REJECTED` or `CANCELLED` at various stages. See detailed state transitions and what triggers each status change. #### Loan Products Loan products define the terms and conditions for different types of loans: * **Interest Rates** - Fixed or variable rates * **Tenure Options** - Available loan periods (e.g., 3, 6, 12, 24 months) * **Eligibility Criteria** - Requirements customers must meet * **Fee Structure** - Processing fees, late fees, etc. * **Min/Max Amounts** - Loan amount limits Understand how loan products are configured and selected. #### Credit Assessment The platform uses multiple data sources for credit assessment: * **Credit Bureau Integration** - Access to credit history and scores * **Transaction Analysis** - Analysis of customer transaction patterns * **Alternative Data** - Employment, income, and other verification data * **Risk Models** - Custom risk scoring algorithms Explore credit assessment methods and risk models. #### Repayment Schedules Repayment schedules are automatically generated based on: * **Loan Amount** - Principal amount disbursed * **Interest Rate** - Annual interest rate * **Tenure** - Loan period in months * **Repayment Frequency** - Monthly, weekly, or custom intervals Understand repayment calculation and schedule generation. ### Integration Quick Start Before you begin: Contact our team to receive your sandbox API keys and base URL. Familiarize yourself with our [Lending API Reference](/api/lending/loan-request). Read through the [Application Flow](/lending/process-flow) to understand the complete loan journey. Explore all available lending endpoints with request/response examples. ### Loan Application Process #### 1. Customer Applies for Loan Customers select a loan product and submit an application with: * Requested loan amount * Preferred tenure (if applicable) * Eligibility question answers * Additional documentation (if required) #### 2. System Processing The system automatically: * Validates application data * Checks eligibility criteria * Performs initial credit assessment * Routes to appropriate workflow #### 3. Manual/Automatic Underwriting Review Loan officers review applications and: * Assess creditworthiness * Verify customer information * Make approval/rejection decisions * Set final loan terms (amount, rate, tenure) #### 4. Offer & Acceptance Once approved: * System sends loan offer to customer with terms * Customer reviews and accepts the offer * And then proceeds to also accept the loan terms * Application status updates to ACCEPTED #### 5. Loan Disbursement & Withdrawal Once the offer is accepted: * A **wallet account** is automatically created for the customer * The loan amount is disbursed into this wallet * Customers can view their total approved loans To access the funds: 1. **Add Bank Account** - Customer verifies and adds their bank account 2. **Withdraw Funds** - Initiate transfer from wallet to bank account 3. **Transfer History** - Track status of all withdrawals Withdrawals attract a small processing fee (e.g., 10 Naira) applied by the payment processor. #### 6. Repayment Management Customers make repayments and the system: * Tracks payment history * Updates loan balance * Manages overdue accounts * Generates reports Detailed step-by-step process flow. ### Supported Features #### Automated Eligibility Checks * Product-specific eligibility rules * Dynamic field requirements * Real-time validation * Automated decision making (where applicable) #### Credit Bureau Integration * Real-time credit checks * Credit score retrieval * Credit report analysis * Risk assessment #### Flexible Repayment Options * Multiple payment methods (wallet, bank transfer, cash) * Partial repayments * Early settlement * Payment rescheduling (with approval) Explore repayment options and processes. ### Testing & Sandbox We provide a full-featured sandbox environment for testing: * **Sandbox URL**: `https://{domain}.fincode.software` * **Test credentials**: Provided upon registration * **Mock credit bureau**: Simulate credit checks * **No real money**: All transactions are simulated Use the sandbox to test all flows, edge cases, and error handling before going live. ### Integration Models We support flexible integration approaches: ### End-to-End Integration Build the complete lending experience within your application, managing the entire customer journey from application to repayment. **Flow**: 1. Customer registration and KYC 2. Loan product selection 3. Application submission 4. Underwriting and approval 5. Disbursement 6. Repayment management **Documentation**: * [Complete Application Flow](/lending/process-flow) * [Loan Request API](/api/lending/loan-request) * [Authentication](/api/auth/login) ### Direct API Integration If you manage your own customer interface, you can integrate our lending APIs directly into your system. **Flow**: ``` Your System (Customer Interface) ↓ Submit Loan Application (via API) ↓ Our System (Processing + Underwriting) ↓ Your System (Receive Status Updates via Webhooks) ↓ Loan Disbursed / Rejected ``` **What You Handle**: * Customer interface and experience * Application data collection * Status display and notifications **What We Handle**: * Eligibility checks * Credit assessment * Underwriting workflow * Disbursement * Repayment tracking All loan operations are accessible via our REST APIs. See the [API Reference](/api/lending/loan-request) for details. ## Next Steps Visualize the complete loan application journey with detailed diagrams Understand loan states and transitions from application to completion Learn about credit assessment and risk evaluation Jump into the API documentation and begin building # Process Flow Source: https://docs.fincode.technology/lending/process-flow This guide details the complete customer journey for digital lending, from application to disbursement and withdrawal. The flow covers **Application**, **Offer**, **Acceptance**, **Disbursement**, **Withdrawal**, and **Repayment**. ### Phase 1: Loan Application #### 1.1 Product Selection & Eligibility The customer starts by viewing available loan products and answering eligibility questions. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant LoanService Customer->>App: View Loan Products App->>API: GET /list-products API-->>App: Return Products List Customer->>App: Select Product App->>API: GET /loan-eligibility-questions/{id} API-->>App: Return Dynamic Questions Customer->>App: Answer Questions Note right of Customer: Enter BVN, Phone, Income, Country Customer->>App: Submit Application App->>API: POST /request-loan API-->>App: Application Submitted ``` View available loan products View dynamic eligibility questions #### Application Steps Customer views the list of available loan products and selects one. System returns dynamic eligibility questions based on the selected product. Customer provides answers along with key details: * **Employment Status** * **BVN** * **Phone Number** * **Monthly Income** * **Country** ### Phase 2: Processing & Offer #### 2.1 Status & Offer Generation After submission, the application undergoes review (manual or automated). ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant Admin Customer->>App: Check Status App->>API: GET /get-loan-history/{id} API-->>App: Return Application Status rect rgb(240, 248, 255) Note over API, Admin: Internal Processing Admin->>Admin: Review Application Admin->>API: Approve & Make Offer end Customer->>App: View Offer App->>API: GET /get-loan-offer API-->>App: Return Offer Details ``` View loan history View loan offer ### Phase 3: Acceptance #### 3.1 Accept or Reject Offer The customer reviews the loan offer and terms. Customer sees the approved amount (which may be less than or equal to requested). Customer proceeds to accept or reject the loan offer. If accepting, customer accepts the specific loan terms. Accept loan offer Reject loan offer Accept loan terms ### Phase 4: Disbursement & Wallet #### 4.1 Wallet Creation Once the loan is disbursed by the admin: 1. A **wallet account** is automatically created for the customer. 2. The loan amount is credited to this wallet. 3. The customer can view their total approved loans. View total approved loans ### Phase 5: Withdrawal #### 5.1 Add Bank Account To withdraw funds, the customer must first add a valid bank account. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant BankService Customer->>App: Select "Add Bank" App->>API: GET /get-available-banks API-->>App: List of Banks Customer->>App: Select Bank & Enter Account No App->>API: GET /verify-bank-account/{code}/{number} API->>BankService: Verify Details BankService-->>API: Return Customer Name API-->>App: Verification Success Customer->>App: Confirm Add App->>API: Add to Customer Accounts ``` View available banks Verify bank account #### 5.2 Withdraw Funds The customer transfers funds from their wallet to their bank account. A processing fee (e.g., 10 Naira) is applied to withdrawals. 1. **Select Source**: Choose the DISBURSED loan/wallet. 2. **Select Destination**: Choose a saved customer bank account. 3. **Enter Details**: Input amount and optional narration. 4. **Confirm**: Send funds. View customer bank accounts #### 5.3 Track Transfers Customers can view the history and status of their transfers. View transfer history Manage loans ### Phase 6: Repayment After loan disbursement, customers need to make repayments according to their loan schedule. The system supports both partial repayments and full payoff. #### 6.1 View Repayment Information Customers can view their pending repayments and get detailed repayment instructions. ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant LoanService Customer->>App: Check Repayments App->>API: GET /pending-repayments/{user-id} API->>LoanService: Fetch Pending Repayments LoanService-->>API: Return Repayments API-->>App: List of Pending Repayments Customer->>App: Get Instructions App->>API: GET /repayment-instructions/{loan-application-id} API->>LoanService: Fetch Instructions LoanService-->>API: Return Instructions API-->>App: Bank Account & Reference App-->>Customer: Display Instructions ``` View pending repayments Get repayment instructions #### 6.2 Make Repayment Customers can make partial repayments or pay off the entire loan. **Partial Repayment**: 1. Customer makes a bank transfer to the provided account with repayment reference 2. Customer records the repayment via API: `POST /repay-loan/{user-id}` 3. System records repayment with status `PENDING_VERIFICATION` 4. System verifies payment and updates loan balance **Full Payoff**: 1. Customer initiates payoff: `POST /payoff-loan` 2. System calculates total balance (principal + accrued interest) 3. Customer makes payment and records it 4. System verifies and closes the loan Make partial repayment Pay off entire loan #### 6.3 Track Repayment History Customers can view their complete repayment history and loan details. View repayment history View loan with payment history See detailed repayment flow documentation with diagrams and examples. Some loans may use third-party collection services. In such cases, manual repayments via API may not be allowed. Always check the loan's repayment collection configuration. # Repayment Flow Source: https://docs.fincode.technology/lending/repayment-flow This guide details the complete repayment flow for digital lending, from viewing repayment information to making payments and tracking repayment history. The repayment flow covers **Viewing Repayment Information**, **Making Repayments**, **Payoff**, and **Tracking History**. ## Phase 1: View Repayment Information ### Check Pending Repayments Customers can view all their pending repayments across all active loans. View all pending repayments View loan details and manage loans ### Get Repayment Instructions Before making a repayment, customers can retrieve detailed repayment instructions including bank account details and payment reference. Get detailed repayment instructions ## Phase 2: Make Repayment ### Partial Repayment Customers can make partial repayments (installments or custom amounts) for their loans. Make a partial repayment View repayment history ### Full Payoff Customers can pay off their entire loan balance in a single transaction. Pay off entire loan balance ### Repayment Process 1. **Choose Repayment Type**: Customer selects either partial repayment or full payoff. 2. **Provide Payment Details**: For partial repayment: * **Repayment Amount**: Amount to pay * **Customer ID**: Customer identifier * **Account ID**: Loan account identifier * **Bank Account ID**: Source bank account * **Repayment Reference**: Payment reference (if paid externally) * **Payment Date**: Date payment was made * **Payment Narration**: Optional description 3. **Submit Repayment**: System processes the repayment: * Validates loan status (must not be CLOSED) * Checks if manual repayment is allowed * Records the repayment * Updates loan balance * Returns confirmation with repayment details 4. **Verification**: Repayments are recorded with status `PENDING_VERIFICATION`: * System verifies the payment * Once verified, loan balance is updated * Customer receives confirmation Some loans may use third-party collection services (e.g., Remita). In such cases, manual repayments through the API may not be allowed. Customers should use the designated third-party channel for repayments. ## Phase 3: Repayment Methods ### Manual Bank Transfer For loans that allow manual repayment: 1. **Get Repayment Instructions**: Retrieve bank account details and payment reference 2. **Make Bank Transfer**: Transfer funds to the provided account with the reference 3. **Record Repayment**: Submit repayment details via API 4. **Verification**: System verifies the payment and updates loan balance Always include the repayment reference in your bank transfer narration to ensure proper matching and verification. ### Third-Party Collection For loans configured with third-party collection: 1. **Check Collection Channel**: System indicates if third-party collection is required 2. **Use Designated Channel**: Make payments through the specified third-party service 3. **Automatic Verification**: Third-party service verifies and updates the loan automatically If a loan uses third-party collection, manual repayments via the API will be rejected. Always check the loan's repayment collection configuration. ## Phase 4: Track Repayment History ### View Repayment History Customers can view their complete repayment history for all loans. View all repaid transactions View loan history ### View Loan Details with Installment Schedule Customers can view detailed loan information including payment history and complete installment schedule. View loan details with installment schedule and payment history ## Key Concepts ### Repayment Status Repayments go through different statuses: * **PENDING\_VERIFICATION**: Repayment has been recorded but not yet verified * **VERIFIED**: Repayment has been verified and loan balance updated * **REJECTED**: Repayment verification failed (e.g., incorrect reference, insufficient funds) ### Payment Allocation When a repayment is made, the system allocates the payment in the following order (based on loan product configuration): 1. **Penalties** (if any) 2. **Fees** (if any) 3. **Interest** 4. **Principal** Return to lending overview # Underwriting Source: https://docs.fincode.technology/lending/underwriting The underwriting process is the core of the lending platform, determining the creditworthiness of applicants and structuring loan offers. Our system supports a hybrid approach combining automated checks with manual review capabilities. ## Underwriting Workflow ```mermaid theme={null} flowchart TD A[Application Submitted] --> B{Automated Checks} B -->|Pass| C[Credit Scoring] B -->|Fail| D[Auto-Rejection] C --> E{Risk Score} E -->|High Risk| D E -->|Low/Medium Risk| F[Manual Review Queue] F --> G{Loan Officer Decision} G -->|Approve| H[Set Terms & Offer] G -->|Reject| D ``` ## 1. Automated Checks Immediately upon submission, the system performs a series of validation checks: ### Eligibility Rules * **Age Verification**: Checks if the applicant meets the minimum/maximum age requirements. * **Location**: Verifies if the applicant is in a supported region/country. * **Employment Status**: Filters allowed employment types (e.g., Salaried, Self-Employed). ### KYC Verification * **Identity Check**: Validates BVN (Bank Verification Number) against the national database. * **Blacklist Check**: Screens the applicant against internal and external blacklists (AML/CFT). View how dynamic eligibility questions are retrieved. ## 2. Credit Scoring For applications that pass initial checks, the system calculates a credit score using multiple data points: * **Bureau Data**: Credit history, existing debts, and repayment behavior from credit bureaus. * **Platform Data**: Transaction history, wallet balance, and previous loan performance on our platform. * **Alternative Data**: Income estimation based on bank statement analysis (if integrated). The result is a **Risk Score** (e.g., 0-100) that categorizes the applicant: * **Green (Low Risk)**: High likelihood of approval. * **Amber (Medium Risk)**: Requires careful manual review. * **Red (High Risk)**: Recommended for rejection. ## 3. Manual Review Loan officers use the Admin Dashboard to review applications in the queue. ### Review Actions 1. **Verify Documents**: Review uploaded ID cards, payslips, or bank statements. 2. **Analyze Risk**: View the calculated Risk Score and detailed credit report. 3. **Decision Making**: * **Approve**: The officer can approve the loan. * **Reject**: The officer can reject the loan with a specific reason code. ### Setting Loan Terms Upon approval, the loan officer determines the final terms of the offer: * **Approved Amount**: Can be equal to or less than the requested amount. * **Interest Rate**: Set based on the risk profile and product configuration. * **Tenure**: Finalized repayment period. ## Decision Outcomes ### Approval If approved, the application moves to the `APPROVED` state. The system generates a loan offer containing the finalized terms, which is then made available to the customer. See how customers retrieve their approved offer. ### Rejection If rejected, the application moves to the `REJECTED` state. The customer is notified, and depending on configuration, may be eligible to re-apply after a cooling-off period. # System Architecture Source: https://docs.fincode.technology/overview/architecture FinCode is built on a modern, cloud-native microservices architecture designed for scalability, security, and high availability. This ensures that our platform can handle high transaction volumes while maintaining strict compliance and data integrity. ## High-Level Overview The platform exposes a unified API Gateway that routes requests to specific backend services. This decouples the client applications from the underlying service complexity. ```mermaid theme={null} graph TD Client[Client Apps / Partners] -->|HTTPS / JSON| Gateway[API Gateway] subgraph "Core Services" Gateway --> Auth[Auth Service] Gateway --> Transaction[Transaction Engine] Gateway --> Compliance[Compliance Engine] Gateway --> Ledger[Ledger Service] Gateway --> Notification[Notification Service] end subgraph "External Integrations" Transaction --> Banks[Banking Partners] Transaction --> Mobile[Mobile Money Providers] Compliance --> Sanctions[Sanctions Lists] end ``` ## Core Components ### API Gateway The entry point for all external traffic. It handles: * **Routing**: Directs requests to the appropriate microservice. * **SSL Termination**: Decrypts incoming traffic. ### Security & Authentication Manages user identities and access control. * **JWT Management**: Issues and validates JSON Web Tokens. * **RBAC**: Enforces Role-Based Access Control policies. ### Transaction Engine The heart of the platform, responsible for the end-to-end lifecycle of a remittance. * **Orchestration**: Coordinates between compliance, ledger, and payout providers. * **State Management**: Tracks transaction status (e.g., `WAITING_TO_PAY`, `PAID`). ### Compliance Engine Ensures all transactions meet regulatory standards. * **AML/KYC**: Performs automated checks on senders and beneficiaries. * **Sanctions Screening**: Checks against global watchlists. ### Ledger Service A double-entry accounting system that records every financial movement. * **Immutability**: Ensures financial data cannot be tampered with. * **Reconciliation**: Facilitates daily settlement and reconciliation. ## Integration Patterns We support multiple integration patterns to suit different needs: * **REST API**: Synchronous request-response model for initiating transactions and querying data. * **Webhooks**: Asynchronous event notifications (e.g., `transaction.completed`) pushed to your server. # Multitenancy Source: https://docs.fincode.technology/overview/multitenancy FinCode is built on a robust multi-tenant architecture designed to support complex hierarchies of financial institutions, agents, and sub-agents. This ensures that data is securely isolated while allowing for flexible configuration inheritance. ## Architecture Overview The platform operates on a **Principal-Agent** model: * **Principal (Tenant)**: The top-level entity (e.g., a Money Transfer Operator or Bank) that owns the platform instance. The Principal configures global settings, compliance rules, and liquidity providers. * **Agent**: A business entity operating under the Principal. Agents can have their own customers, branding, and specific configurations, but they operate within the limits set by the Principal. * **Sub-Agent**: A further subdivision under an Agent, often used for retail locations or specific branches. ```mermaid theme={null} graph TD Principal[Principal / Tenant] --> AgentA[Agent A] Principal --> AgentB[Agent B] AgentA --> SubAgent1[Sub-Agent 1] AgentA --> SubAgent2[Sub-Agent 2] ``` ## Data Isolation Data security and privacy are paramount in a multi-tenant environment. * **Logical Isolation**: All data (customers, transactions, beneficiaries) is logically isolated by a unique `tenantId` (often referred to as `agents` or `platform` context in APIs). * **Access Control**: Users are assigned roles within a specific tenant context. An admin for "Agent A" cannot access data belonging to "Agent B". * **Request Context**: Every API request requires context in the request url (like `https://${domain}.fincode.software`) to ensure the operation is performed against the correct tenant partition. ## Configuration Inheritance To simplify management, the platform uses a hierarchical configuration system. ### Inheritance Rules 1. **Global Defaults**: The Principal sets global defaults for fees, exchange rate margins, and transaction limits. 2. **Agent Overrides**: Agents can be configured to inherit these defaults or have specific overrides applied to them. 3. **Specific Rules**: If an Agent has a specific rule (e.g., a lower fee for a marketing campaign), it takes precedence over the global default. ## White-Labeling The platform supports extensive white-labeling to ensure a consistent brand experience for each tenant. * **Branding**: Logos, color schemes, and fonts can be customized per Agent. * **Communication**: Email templates and SMS notifications can be branded to appear as if they are coming directly from the Agent. * **URLs**: Agents can operate on their own subdomains (e.g., `agent-a.remitjunction.com`). # Security Source: https://docs.fincode.technology/overview/security At FinCode, we prioritize the security of your data and transactions. This guide outlines our security architecture and provides best practices for securing your integration. ## Authentication & Authorization FinCode uses a robust **Role-Based Access Control (RBAC)** system powered by **JWT (JSON Web Tokens)**. Most API requests are authenticated and authorized to ensure that users and systems can only access the resources they are permitted to. For detailed authentication guides, refer to the [Authentication](/authentication) documentation. ## Server-to-Server Security When integrating your backend systems with FinCode (Server-to-Server), securing your credentials and tokens is critical. Unlike client-side integrations, server-side integrations often have elevated privileges. ### Credential Management Your authentication credentials (email/password or API token) are the keys to your tenant. **Never hardcode credentials** in your source code. * **Environment Variables**: Store credentials in environment variables on your server. * **Secrets Management**: Use a dedicated secrets manager (e.g., AWS Secrets Manager, HashiCorp Vault, Azure Key Vault) to inject credentials at runtime. * **Version Control**: Ensure credentials are never committed to git repositories. Use `.gitignore` to exclude configuration files. ### Token Handling Since our JWTs are short-lived (typically 1 hour), your server must handle token lifecycle management efficiently: 1. **In-Memory Caching**: Cache the `access_token` in memory. Do not persist it to disk or databases if possible. 2. **Automatic Refresh**: Implement logic to check token expiration before making requests. If the token is expired (or about to expire), use the `refresh_token` to get a new one. 3. **Secure Storage**: If you must persist tokens (e.g., `refresh_token`), encrypt them at rest using strong encryption standards (AES-256). ## Data Protection ### Encryption in Transit All communication between your systems and FinCode is encrypted using **TLS 1.2+** (Transport Layer Security). We enforce HTTPS for all API endpoints to protect data against interception and tampering. ### Encryption at Rest Sensitive data stored within the FinCode platform is encrypted at rest using industry-standard **AES-256** encryption. This includes PII (Personally Identifiable Information) and transaction details. ## Network Security * **IP Whitelisting**: (If applicable to your plan) Configure IP whitelisting to restrict API access to your known server IP addresses. * **DDoS Protection**: Our infrastructure is protected by enterprise-grade DDoS mitigation systems. ## Compliance & Privacy FinCode adheres to strict financial regulations and data privacy standards. * **GDPR/NDPR**: We are compliant with data protection regulations, ensuring your user's data is handled with care. * **PCI DSS**: Payment processing components are PCI DSS compliant to ensure the security of card data. ## Reporting Vulnerabilities If you discover a potential security vulnerability, please report it immediately to our security team at [hello@fincode.co.uk](mailto:hello@fincode.co.uk). We appreciate your help in keeping our platform secure. # Quick Start Guide Source: https://docs.fincode.technology/quickstart Get your integration up and running in under 15 minutes. Get started with FinCode's multitenant platform in three simple steps. This guide will walk you through account setup, authentication, and making your first API call. ## Step 1: Account Setup & Due Diligence Before you can start integrating, you will need to complete our general onboarding process with the following steps: 1. **Submit Application**: Visit [fincode.co.uk/contact-us](https://fincode.co.uk/contact-us) to begin your application. 2. **Provide Documentation**: Submit required business documents. 3. **KYC/KYB Verification**: Complete the different verification processes. 4. **Compliance Review**: Our team will review your application (typically 2-3 days). 5. **Account Approval**: Receive approval notification with your sandbox details. Have your business registration documents, proof of address, and compliance certificates ready to speed up the process. Once approved, you'll receive your unique sandbox credentials: ### Your Domain Format ``` https://{domain}.fincode.software ``` Your domain is your dedicated environment where all your API calls will be made. This ensures complete tenant isolation and data security. Your domain will be provided in your approval email. Keep this information secure as it's required for all API requests. After approval, you'll have access to two environments: * **Sandbox**: `https://{domain}.fincode.software/sandbox` * **Production**: `https://{domain}.fincode.tech` Log in to your dashboard at your domain to access: * API documentation specific to your tenant * Sandbox test data and accounts * Configuration settings * Webhook management * Analytics and reporting Always test thoroughly in sandbox before moving to production. ## Step 2: Generate API Tokens 1. Populate Login Details and login through the API 2. Generate a token for selected environment or service on your dashboard ### Protecting Your Tokens * Never commit tokens to version control * Use environment variables for token storage * Rotate tokens every 90 days or when compromised * Use least-privilege principle - only grant necessary permissions * Monitor token usage in your dashboard ### Environment Variables Setup ```bash theme={null} # Add to your .env file DOMAIN=domain JWT_ACCESS_TOKEN=fct_sandbox_your_token_here FINCODE_BASE_URL=https://{domain}.fincode.software ``` If you suspect a token has been compromised, revoke it immediately from your dashboard. ## Step 3: Make Your First API Call Test your authentication by logging in via API. This will verify your setup and return an access token for subsequent requests. ```javascript theme={null} const axios = require('axios'); const DOMAIN = process.env.DOMAIN; const JWT_ACCESS_TOKEN = process.env.JWT_ACCESS_TOKEN; const BASE_URL = `https://${DOMAIN}.fincode.software`; async function login() { try { const response = await axios.put( `${BASE_URL}/api/v6/services/securitymanagement/login`, { email: 'your-email@company.com', currentPassword: 'your-password' }, { headers: { 'Content-Type': 'application/json', 'uuid': 200, 'platform': 'fincode' } } ); console.log('Login successful!'); console.log('Access Token:', response.data.token); return response.data; } catch (error) { console.error('Login failed:', error.response?.data || error.message); throw error; } } login() .then(data => { const accessToken = data.access_token; console.log('Ready to make API calls!'); }) .catch(err => { console.error('Authentication error:', err); }); ``` **Expected Response:** ```json theme={null} { "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "modules": ["REMITTANCE", "LENDING"], "country": "Nigeria", "expires_in": 3600, "organisation": "def50200a1b2c3d4e5f6...", "profileDetailsResponseDTO": { "phone": "448182147656", "dob": "1994-02-24", "email": "your-email@company.com", "userType": "REGISTERED_CUSTOMER", "id": "8ecca811-607f-44e1-a57e-cd856c50437d", "accessScope": "CUSTOMER_FLOW", } } ``` ```java theme={null} import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.http.HttpRequest.BodyPublishers; import com.google.gson.Gson; import com.google.gson.JsonObject; public class FinCodeAuth { private static final String DOMAIN = System.getenv("DOMAIN"); private static final String JWT_ACCESS_TOKEN = System.getenv("JWT_ACCESS_TOKEN"); private static final String BASE_URL = String.format( "https://%s.fincode.software", DOMAIN ); public static class LoginResponse { public String token; public String role; public int currencyCode; public String twoFactorEnabled; public String organisation; public ProfileDetailsResponseDTO user; public static class User { public String id; public String firstName; public String lastName; public String phone; } } public static LoginResponse login(String email, String currentPassword) throws Exception { HttpClient client = HttpClient.newHttpClient(); Gson gson = new Gson(); JsonObject requestBody = new JsonObject(); requestBody.addProperty("email", email); requestBody.addProperty("currentPassword", currentPassword); // Build request .uri(URI.create(BASE_URL + "/api/v6/services/securitymanagement/login")) .header("Content-Type", "application/json") .header("uuid", "200") .header("platform", "fincode") .PUT(BodyPublishers.ofString(gson.toJson(requestBody))) .build(); HttpResponse response = client.send( request, HttpResponse.BodyHandlers.ofString() ); if (response.statusCode() == 200) { System.out.println("Login successful!"); LoginResponse loginResponse = gson.fromJson( response.body(), LoginResponse.class ); System.out.println("Access Token: " + loginResponse.token); return loginResponse; } else { throw new Exception("Login failed: " + response.body()); } } public static void main(String[] args) { try { LoginResponse response = login( "your-email@company.com", "your-password" ); String accessToken = response.token; System.out.println("Ready to make API calls!"); } catch (Exception e) { System.err.println("Authentication error: " + e.getMessage()); e.printStackTrace(); } } } ``` ```bash theme={null} curl -X PUT "https://{domain}.fincode.software/api/v6/services/securitymanagement/login" \ -H "Content-Type: application/json" \ -H "uuid: 200" \ -H "platform: fincode" \ -d '{ "email": "your-email@company.com", "currentPassword": "your-password" }' ``` ## Next Steps Now that you're authenticated, choose your product to continue: * Create beneficiary * Get FX quote * Send transaction * Create customer * Submit application * Check decision * Create account * Add portfolio * Execute trades *** ## Common Issues & Troubleshooting **401 Unauthorized** * Verify your API token is correct and not expired * Ensure you're using the correct domain * Check that your token has the necessary permissions **403 Forbidden** * Your account may not have access to the requested resource * Contact support to verify your tenant permissions Access tokens expire after 1 hour. Use the refresh token to get a new access token: ```javascript theme={null} const response = await axios.post( `${BASE_URL}/api/v6/services/securitymanagement/refresh`, { refresh_token: refreshToken }, { headers: { 'Content-Type': 'application/json', 'X-API-Token': JWT_ACCESS_TOKEN } } ); ``` * **Documentation**: Browse our [API Reference](/api/authentication) * **Support**: Email [hello@fincode.co.uk](mailto:hello@fincode.co.uk) * **System Status**: Check [status.fincode.com](https://status.fincode.com) * **Community**: Visit our [GitHub](https://github.com/fincodeuk) for examples # Agent Integration Guide Source: https://docs.fincode.technology/remittance/agent-integration This page lists every endpoint your application needs to go live. Work through the sections in order - each section's output feeds the next. **Base URL**: `https://{domain}.fincode.software/api/v6/services/` Replace `{domain}` with the subdomain assigned to your organisation. *** Use this mode when the customer interacts directly with your application in real time - the sender authenticates, completes KYC, and books their own transactions. Work through the steps in order. *** ## Step 1 - Customer Registration Registers a new customer account in the system. This endpoint is designed to reduce the number of API calls required from sign-up to KYC/AML submission. It presents the option to combine sign-up and KYC/AML documents into a single call. Call `list-organisation-compliance-policy` first to obtain your organisation's KYC/AML requirements and understand what to include. The endpoint: * Creates a customer profile with personal or company information * Validates and stores address information * Processes dynamic fields based on organisation configuration * Performs external screening validation for the registration country * Initiates compliance checks for the newly registered customer | Method | Path | What it does | Swagger | | - | - | - | - | | `POST` | [`usermanagement/register-customer`](/api/ciam/create-customer) [→](/api/ciam/create-customer) | Register a new sender | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/user-management/registerCustomer) | | `GET` | [`usermanagement/profile`](/api/ciam/profile) [→](/api/ciam/profile) | Retrieve a sender's profile | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/user-management/profileDetails) | Subscribe to webhook notifications to receive real-time customer status updates. *** ## Step 2 - Authentication Authenticates a user and grants access to the system. Performs comprehensive security checks including email and password validation, IP whitelisting, login security rule enforcement, user status verification, and two-factor authentication when enabled. Upon successful authentication the endpoint returns an `X-Auth-Token` valid for **50 minutes**, shared across all calls within the session. | Method | Path | What it does | Swagger | | - | - | - | - | | `PUT` | [`securitymanagement/login`](/api/auth/login) [→](/api/auth/login) | Obtain a session token | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/security-management/login) | | `GET` | [`securitymanagement/reset-password/{email}`](/api/ciam/reset-password) [→](/api/ciam/reset-password) | Initiate a password reset | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/security-management/resetPassword) | | `PUT` | [`securitymanagement/change-password`](/api/ciam/change-password) [→](/api/ciam/change-password) | Change the authenticated user's password | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/security-management/changePassword) | *** ## Step 3 - KYC & Compliance When a customer is registered, the platform automatically assigns KYC rules based on their risk profile. The compliance checklist may include: * Document verification requirements (passport, national ID, proof of address) * Transaction limits and thresholds that apply to the customer * Identity verification methods (email, phone, eKYC) * Risk assessment requirements * AML/KYC screening requirements * Geographic and delivery method restrictions Call `list-organisation-compliance-policy` to retrieve your organisation's KYC policy, then call `customer-compliance-checklist` to find out what actions are outstanding for a specific customer before a transaction can be booked. | Method | Path | What it does | Swagger | | - | - | - | - | | `GET` | [`compliance/list-organisation-compliance-policy`](/api/ciam/list-organisation-compliance-policy) [→](/api/ciam/list-organisation-compliance-policy) | Retrieve the KYC and transaction rules configured for the organisation | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/Complaince%20Management%20Service/listComplianceRules) | | `PUT` | [`compliance/customer-compliance-checklist`](/api/ciam/compliance-checklist) [→](/api/ciam/compliance-checklist) | Retrieve the pre-transaction compliance checklist for a customer | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/Complaince%20Management%20Service/preTransactionBookingComplianceCheckList) | From here, the flow depends on whether you are using the platform's built-in KYC or your own external KYC provider. ### Initiate each requirement For each item returned by the compliance checklist, call the initiate endpoint. This triggers the action on the platform side and returns what you need to proceed. | Method | Path | What it does | Swagger | | - | - | - | - | | `GET` | [`compliance/initiate-awaiting-compliance-action/{customer-kyc-record-id}`](/api/ciam/initiate-compliance-action) [→](/api/ciam/initiate-compliance-action) | Trigger a specific pending KYC action | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/Complaince%20Management%20Service/initiateAwaitingComplianceActionById) | Replace `{customer-kyc-record-id}` with the ID from the checklist. ### Fulfil each requirement How each action is fulfilled depends on its type. Handled automatically. When you call initiate, the platform sends a branded verification email to the customer. No further API call is needed from your side. The platform sends an OTP to the customer via SMS when you call initiate. Your application collects the code from the customer and submits it. | Method | Path | What it does | Swagger | | - | - | - | - | | `GET` | [`securitymanagement/otp-verification/{email}/{verification-code}`](/api/ciam/otp-verification) [→](/api/ciam/otp-verification) | Submit the OTP the customer received | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/security-management/smsVerification) | | `GET` | [`securitymanagement/sms-resend-otp/{email}`](/api/ciam/sms-resend-otp) [→](/api/ciam/sms-resend-otp) | Resend the OTP if the customer did not receive it | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/security-management/smsResend) | Your application collects the document from the customer and submits it. | Method | Path | What it does | Swagger | | - | - | - | - | | `POST` | [`documentmanagement/attach-documents`](/api/ciam/attach-documents) [→](/api/ciam/attach-documents) | Submit a KYC or AML document | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/document-management-web-service/attachDocuments) | Pass the `associatedRuleId` from the checklist item in the request body to link the document to the correct rule. The initiation call automatically creates the eKYC session. Follow the flow returned in the initiate response to complete electronic identity verification. ### Prerequisites - Plugin setup Before using your own KYC provider, you must configure it as a plugin on your agent dashboard. 1. Go to the **Plugins** section on your dashboard. 2. Click **Create Plugin** and enter your provider credentials. 3. Set the **API Type** to **EXTERNAL KYC PROVIDER**. If your provider handles email and phone verification as part of its identity flow, also enable the following settings to prevent the platform from sending its own verification messages to the customer: * **doNotForwardEmailVerification**: prevents the platform from sending its own email verification link. * **doNotForwardPhoneVerification**: prevents the platform from sending its own phone OTP. *** ### Register the eKYC session with the platform Before initiating verification with your provider, call this endpoint to create a tracking record on the platform side. The platform generates a unique `reference` and returns it. | Method | Path | What it does | Swagger | | - | - | - | - | | `POST` | [`compliance/external-provider/initiate`](/api/ciam/initiate-external-provider) [→](/api/ciam/initiate-external-provider) | Register the eKYC session and obtain a platform reference | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/Complaince%20Management%20Service/initiateExternalKycProvider) | Store the `reference` from the response. Pass it to your KYC provider as the external user identifier so the provider echoes it back in the webhook it sends to the platform. *** ### Configure the webhook callback Your KYC provider must send its verification result directly to the platform when the customer completes verification. Configure the URL below as the webhook callback in your provider account settings. This is a one-time setup, not per customer. | Method | Path | What it does | Swagger | | - | - | - | - | | `POST` | [`compliance/external-screening/webhooks/{provider-code}`](/api/ciam/external-screening-webhook) [→](/api/ciam/external-screening-webhook) | Receives verification results from your KYC provider | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/Complaince%20Management%20Service/handleExternalScreeningWebhook) | Replace `{provider-code}` with the value that matches your KYC provider (see [Supported Providers](#supported-kyc-providers) below). *** ### Initialise verification with your provider Create the verification session with your KYC provider and embed the `reference` from the registration step in the field your provider uses for an external reference. The provider will echo this value back in the webhook it sends to the platform on completion. *** ### Listen for the platform webhook After the platform processes the result, it will POST a webhook to your registered callback URL with: ```json theme={null} { "eventType": "COMPLIANCE_RISK_PROFILE_UPDATED" } ``` Check the `customerKycVerificationRecordEntity` array in the payload. Any rule with `"executed": false` is still outstanding and must be fulfilled before the customer can transact. *** ### Fulfil non-eKYC requirements If your provider also handles email and phone verification, notify the platform after your provider has verified each one: | Method | Path | What it does | Swagger | | - | - | - | - | | `POST` | [`compliance/external-provider/verify-contact`](/api/ciam/verify-contact) [→](/api/ciam/verify-contact) | Mark email or phone as verified | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/Complaince%20Management%20Service/verifyContact) | Pass `userId` and `type` (`EMAIL` or `PHONE_NUMBER`). This marks the requirement as fulfilled and triggers the full KYC lifecycle automatically. When this endpoint is called, the platform also calls your configured KYC provider to independently verify the contact detail. The plugin must be configured before using this endpoint. If your provider does **not** handle email and phone verification, fulfil those requirements using the standard flows: Handled automatically. When you call initiate in the registration step, the platform sends a branded verification email to the customer. No further API call is needed. The platform sends an OTP via SMS. Your application collects the code and submits it. | Method | Path | What it does | Swagger | | - | - | - | - | | `GET` | [`securitymanagement/otp-verification/{email}/{verification-code}`](/api/ciam/otp-verification) [→](/api/ciam/otp-verification) | Submit the OTP the customer received | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/security-management/smsVerification) | | `GET` | [`securitymanagement/sms-resend-otp/{email}`](/api/ciam/sms-resend-otp) [→](/api/ciam/sms-resend-otp) | Resend the OTP if the customer did not receive it | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/security-management/smsResend) | Collect the document and submit it. Pass the `associatedRuleId` from the checklist item in the request body. | Method | Path | What it does | Swagger | | - | - | - | - | | `POST` | [`documentmanagement/attach-documents`](/api/ciam/attach-documents) [→](/api/ciam/attach-documents) | Submit a KYC document | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/document-management-web-service/attachDocuments) | *** ## Step 4 - Transaction Quote Get a live exchange rate and fee breakdown before booking. | Method | Path | What it does | Swagger | | - | - | - | - | | `POST` | [`quote/callQuote`](/api/transactions/call-quote) [→](/api/transactions/call-quote) | Perform a transaction quote | [↗](https://test-remittance-service-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/quote-web-service-6/callQuote) | *** ## Step 5 - Beneficiary Management Add and retrieve beneficiaries linked to a sender. | Method | Path | What it does | Swagger | | - | - | - | - | | `POST` | [`usermanagement/new-beneficiary`](/api/transactions/create-beneficiary) [→](/api/transactions/create-beneficiary) | Add a new beneficiary to a sender's account | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/user-management/newBeneficiery) | | `GET` | [`usermanagement/find-all-beneficiery`](/api/transactions/beneficiary-list) [→](/api/transactions/beneficiary-list) | Retrieve all beneficiaries for a sender | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/user-management/findBeneficiery) | *** ## Step 6 - Book a Transfer Supports two modes. **Sender mode** allows the sender to book a transaction for themselves, creating a new recipient or using an existing one. **Cashier mode** enables a cashier to book a transaction on behalf of a sender - see the **Non-interactive mode** tab for the full cashier flow. Both endpoints require an `X-Idempotency-Key` header to prevent duplicate bookings. | Method | Path | What it does | Swagger | | - | - | - | - | | `POST` | [`transactionmanagement/create-transaction`](/api/transactions/create-transaction) [→](/api/transactions/create-transaction) | Book a transfer | [↗](https://test-remittance-service-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/transaction-management/createTransaction2) | The `X-Idempotency-Key` must be a unique identifier per request. Subscribe to webhook notifications as an alternative to polling the status endpoint. *** ## Step 7 - Pay for a Booked Transfer Retrieves the available payment methods for a booked transfer. Returns available methods based on the transaction details, including online card payments, open banking transfers, e-wallets, bank transfers, cryptocurrency, and cash at payment points. The endpoint: * Validates the authentication token and user credentials * Fetches configured payment gateway integrations for the organisation * Calculates payment method charges and fees for each available option * Validates transaction amounts against payment method limits * Checks compliance requirements and risk profiles * Returns metadata for each supported method including fees, totals, and gateway-specific details | Method | Path | What it does | Swagger | | - | - | - | - | | `POST` | [`paymentmanagement/supported-payment-methods`](/api/deposit-engine/supported-payment-methods) [→](/api/deposit-engine/supported-payment-methods) | List payment methods for a booked transfer | [↗](https://test-deposit-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/payment-management/supportedPaymentMethods) | The `X-Idempotency-Key` must be a unique identifier per request. The `pcn` must match the one used in the booking call. Call this endpoint once per transaction - each call returns a new `paymentIntentId`. *** ## Step 8 - Check Transfer Status Check the current status of a booked transfer by its reference number. | Method | Path | What it does | Swagger | | - | - | - | - | | `GET` | [`transactionmanagement/checktransactionstatus/{pcn}`](/api/transactions/check-transaction-status) [→](/api/transactions/check-transaction-status) | Check the status of a booked transfer | [↗](https://test-remittance-service-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/transaction-management/checkTransactionStatus) | Pass the `pcn` from the `create-transaction` response as the path parameter. Subscribe to webhook notifications to receive automatic status updates without polling. *** ## AML Compliance AML checks run at the point of transaction. Any outstanding requirements must be resolved before the transaction can complete. Submit AML-required documents using the same endpoint as KYC documents. Pass the `associatedRuleId` from the outstanding requirement in the request body. | Method | Path | What it does | Swagger | | - | - | - | - | | `POST` | [`documentmanagement/attach-documents`](/api/ciam/attach-documents) [→](/api/ciam/attach-documents) | Submit an AML-required document | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/document-management-web-service/attachDocuments) | *** ## Summary `POST usermanagement/register-customer` `PUT securitymanagement/login` Built-in KYC: initiate each requirement then fulfil it. Your own KYC provider: register the session, configure the webhook, initiate with your provider, and listen for `COMPLIANCE_RISK_PROFILE_UPDATED`. `POST quote/callQuote` `POST usermanagement/new-beneficiary` `POST transactionmanagement/create-transaction` `POST paymentmanagement/supported-payment-methods` `POST documentmanagement/attach-documents` Poll `checktransactionstatus` or subscribe to webhooks Use this mode for system-to-system integration where your backend books transactions directly on behalf of senders, without the sender being present. A cashier user authenticates on your backend, then calls `create-transaction` in a single request with the sender, beneficiary, and any required KYC documents all embedded in the payload. *** ## Step 1 - Get Organisation Compliance Policy Before booking, call this endpoint to retrieve your organisation's KYC and AML requirements. The compliance policy tells you which documents and fields you must embed in the `create-transaction` request for the sender. The policy includes: * Document verification requirements (passport, national ID, proof of address) * Transaction limits and thresholds * Identity verification methods * AML/KYC screening requirements * Geographic and delivery method restrictions | Method | Path | What it does | Swagger | | - | - | - | - | | `GET` | [`compliance/list-organisation-compliance-policy`](/api/ciam/list-organisation-compliance-policy) [→](/api/ciam/list-organisation-compliance-policy) | Retrieve KYC and transaction rules for the organisation | [↗](https://test-nucleus-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/Complaince%20Management%20Service/listComplianceRules) | *** ## Step 2 - Book Transfer with Embedded KYC Authenticate as a cashier user and call `create-transaction` with everything embedded. This endpoint reduces the number of API calls required from sign-up to booking. It allows you to combine sender creation, beneficiary creation, and KYC document submission into a single call. We recommend calling `customer-compliance-checklist` before `create-transaction` so you can identify and submit any outstanding compliance requirements inline. | Method | Path | What it does | Swagger | | - | - | - | - | | `POST` | [`transactionmanagement/create-transaction`](/api/transactions/create-transaction) [→](/api/transactions/create-transaction) | Book a transfer on behalf of a sender | [↗](https://test-remittance-service-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/transaction-management/createTransaction2) | This endpoint requires three additional headers: `ipAddress` (the sender's IP address), `X-Idempotency-Key` (a unique key per request), and `Merchant-Host`. A missing header returns HTTP 400 with an empty body. ### Sender options Include exactly one of the following in your request: * **New sender** - include the sender's personal details (name, email, phone, address, etc.) in the request body. The platform creates the customer record and returns a `customerCode` in the response. Store this code for subsequent calls. * **Existing sender** - include `preExistingSenderCustomerCode` with the sender's previously assigned code. All sender fields are resolved from the existing record. ### Beneficiary options Include exactly one of the following: * **New beneficiary** - include the recipient's details in `newRecipientKyc` (name, phone, address, destination country, etc.). * **Existing beneficiary** - include the beneficiary's previously assigned code to reuse an existing record. ### Embedding KYC documents Use the `eligibleDocumentList` field to attach any KYC documents required by the compliance policy. Each entry includes the document type and the base64-encoded file. Pass `associatedRuleId` for each document to link it to the correct compliance rule. The response returns a `serverCorrelationId` (the transaction UUID) and a `pcn` (payment reference number) for use in subsequent payment and status calls. *** ## Step 3 - Process Payment (Optional) If the transaction requires a payment link (for example, open banking or card), call this endpoint with the `pcn` from Step 2 to retrieve available payment methods and generate a hosted payment URL. | Method | Path | What it does | Swagger | | - | - | - | - | | `POST` | [`paymentmanagement/supported-payment-methods`](/api/deposit-engine/supported-payment-methods) [→](/api/deposit-engine/supported-payment-methods) | List payment methods for a booked transfer | [↗](https://test-deposit-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/payment-management/supportedPaymentMethods) | Call this endpoint once per transaction. Each call returns a new `paymentIntentId`. Pass the `pcn` from the `create-transaction` response. *** ## Step 4 - Check Transfer Status | Method | Path | What it does | Swagger | | - | - | - | - | | `GET` | [`transactionmanagement/checktransactionstatus/{pcn}`](/api/transactions/check-transaction-status) [→](/api/transactions/check-transaction-status) | Check the status of a booked transfer | [↗](https://test-remittance-service-engine.eks-fincode.com/swagger-ui/index.html?urls.primaryName=customer#/transaction-management/checkTransactionStatus) | Pass the `pcn` from the `create-transaction` response as the path parameter. Subscribe to webhook notifications to receive automatic status updates without polling. *** ## Summary `GET compliance/list-organisation-compliance-policy` `POST transactionmanagement/create-transaction` - include sender (new or existing), beneficiary (new or existing), and any required documents in a single call using a cashier token. `POST paymentmanagement/supported-payment-methods` Poll `checktransactionstatus` or subscribe to webhooks *** ## Supported KYC Providers Applies to integrations using your own KYC provider. The following providers are currently supported. Your chosen provider must be configured in your agent plugin settings before use. | Provider | Code | | - | - | | ShuftiPro | `SHUFTI_PRO` | | SEON | `SEON_IDV` | | SumSub | `SUMSUB` | | Didit | `DIDIT` | ### Technical requirements Your provider must meet all of the following before we can accept their results: * **ID document verification**: must be capable of verifying government-issued identity documents (passport, national ID, driving licence). * **Liveness check (face match)**: must perform a biometric face match between the document photo and a live selfie or video capture. * **Webhook callback support**: must be able to send a webhook to our system when verification is complete. * **Correlation ID embedding**: must accept and return a reference ID in the webhook payload so the platform can tie the result back to the correct customer record. * **Structured result payload**: the webhook payload must include verification outcome, document details, and any AML/sanctions/PEP screening results in a structured, parseable format. # Beneficiary Lifecycle Source: https://docs.fincode.technology/remittance/beneficiary-lifecycle Creating a beneficiary involves a multi-step process to ensure data accuracy and compliance. The flow varies depending on the payout method (Bank Transfer, Cash Pickup, or Mobile Money) but the core process is the same. **Payment Type Configuration**: The available payout methods and their specific configuration are managed at the admin level by the principal firm. This is out of scope for the client integration but determines which options are available for your customers. ### Bank Transfer Flow For Bank Transfers, the process involves validating the bank account details before creating the beneficiary profile and linking the account. #### Step 1: List Supported Banks First, retrieve the list of supported banks for the destination country. View list of supported beneficiary banks #### Step 2: Get Required Fields Different countries and banks require different fields (e.g., IBAN vs. Account Number + Sort Code). Fetch the dynamic requirements for the selected country. View required bank fields #### Step 3: Get Dynamic Forms (Optional) Some corridors require additional sender information when creating a beneficiary. Check for any dynamic fields group `REGISTERED_CUSTOMER_CREATE_BENE`. View dynamic fields #### Step 4: Validate Bank Account Before creation, validate the bank account details. This ensures the account exists and matches the beneficiary name (where supported). View validate bank account endpoint **Response:** If validation is supported and successful, the response will contain the `accountName` which should be used to pre-fill the beneficiary name. #### Step 5: Create Beneficiary Create the beneficiary profile using the validated details. Create beneficiary endpoint #### Step 6: Add Bank Details Finally, link the validated bank account to the newly created beneficiary. This can be done immediately after creation or at a later time. Add bank details endpoint ### Cash Pickup Flow For Cash Pickup, no bank account is required. The beneficiary is identified by their name and phone number only. #### Step 1: Validate Phone (Optional) If supported for the corridor and the payout partner, validate the phone number using the validation endpoint (similar to bank account validation but for phone). View validate mobile number endpoint #### Step 2: Create Beneficiary Create the beneficiary profile. Ensure the `phone` field is populated as it is compulsory for Cash Pickup. Create beneficiary endpoint **Note:** Do not call "Add Bank Details" for Cash Pickup beneficiaries. ### Mobile Money Flow Mobile Money transfers require validating the mobile number with the specific operator(if supported/activated) before creation. #### Step 1: List Mobile Operators Retrieve the list of supported mobile money operators for the destination country. View supported mobile operators #### Step 2: Validate Mobile Number Validate the mobile number and operator code. This checks if the number is active and registered. Use `transactionType: MOBILE_MONEY` and `mobileOperatorCode` **Example Validation Request:** ```json theme={null} { "mobileOperatorCode": "ORANGE", "transactionType": "MOBILE_MONEY", "topUpMobileNumber": "090382738", "accountNumberCountry": "GIN", "expectedCurrencyCode": "GNF" } ``` #### Step 3: Create Beneficiary If validation is successful (or if validation is not supported but the format is correct), create the beneficiary profile. Create beneficiary endpoint #### Step 4: Create Transaction When creating the transaction, include the mobile money details in the `creditParty` array. ```json theme={null} "creditParty": [ {"key": "mobilemoneynumber", "value": "0903827384"}, {"key": "mobileoperatorcode", "value": "ORANGE"} ] ``` # FX Conversion Source: https://docs.fincode.technology/remittance/fx-rates Understanding exchange rates, and how currency conversion works in remittance. Exchange rate management is critical to remittance transactions. FinCode provides real-time exchange rates with transparent pricing, and competitive margins to ensure customers know exactly what they're paying and what beneficiaries will receive. ### Complete Quote Process ```mermaid theme={null} sequenceDiagram participant Customer participant App participant API participant FX Service participant Fee Engine participant Compliance Customer->>App: Enter send amount Customer->>App: Select destination country Customer->>App: Choose payout method App->>API: POST /call-quote Note over App,API: Request includes:
amount, currencies,
corridor, method API->>FX Service: Get live rate FX Service->>FX Service: Fetch from liquidity provider FX Service->>FX Service: Apply FX margin FX Service-->>API: Exchange rate API->>Fee Engine: Calculate fees Fee Engine->>Fee Engine: Check corridor fees Fee Engine->>Fee Engine: Apply amount tier Fee Engine->>Fee Engine: Add payment method fee Fee Engine-->>API: Fee breakdown API->>Compliance: Check limits Compliance->>Compliance: Verify against KYC tier Compliance->>Compliance: Check daily/monthly limits Compliance-->>API: Limit validation API->>API: Calculate totals API-->>App: Complete quote App-->>Customer: Display quote details Note over Customer,App: Rate valid realtime ``` **API Endpoint**: [Call Quote](/api/transactions/call-quote) ### Payment Method Fees Recommended for larger amounts Instant processing For rewards/cashback Best for regular transfers ## Related Documentation See FX in complete transaction flow How funds are delivered after conversion Rates and fees by corridor Complete API documentation Understand transaction states KYC and transaction limits # Overview Source: https://docs.fincode.technology/remittance/overview Welcome to the remittance platform documentation. This guide will help you understand how our international money transfer system works and how to integrate it into your application. ### What is Remittance? Our remittance platform enables **fast, secure, and compliant international money transfers**. Senders can send money across borders to beneficiaries via: * **Bank transfers** - Direct deposits to bank accounts * **Mobile money** - Instant transfers to mobile wallets * **Cash pickup** - Beneficiary collects cash at agent locations ### Key Features Send from GBP, USD, EUR to 50+ destination currencies at competitive exchange rates. Bank transfer, mobile money, and cash pickup options across more than 100+ countries. Automated KYC/AML screening, sanctions checking, and regulatory compliance Live exchange rates with transparent fee structure, markup support and rate adjustments and locking. Most transactions complete within 1-24 hours, with instant options available RESTful APIs with comprehensive documentation and sandbox environment ### How It Works The remittance flow consists of four main phases: Senders register, complete KYC verification, and set up their profile with required compliance documentation. Senders get a quote with live FX rates, select or create beneficiaries, and review transaction details. Secure payment via card or open banking, followed by automated compliance screening and FX conversion. Funds are disbursed to beneficiaries, and both parties receive confirmation notifications. For detailed visual flow, see the [Process Flows](/remittance/process-flows) page. ### Core Concepts #### Transaction Lifecycle Every transaction moves through defined states from creation to completion: ``` WAITING_TO_PAY → VERIFYING → PAID ``` Transactions can also transition to `CANCELLED`, `EXPIRED`, `FAILED_TO_DELIVER`, `PENDING_REFUND`, or `REFUNDED` based on various conditions. See detailed state transitions and what triggers each status change. #### Exchange Rates Exchange rates are fetched in real-time during the transaction process. The final rate includes: * **Base exchange rate** - Market rate from our/your liquidity providers * **FX margin** - Small markup for sustainability * **Transfer fee** - Fixed or percentage-based fee per transaction Understand how FX rates are calculated and applied. #### Beneficiaries Beneficiaries are the recipients of remittance transfers. Senders can: * Save beneficiaries for future transactions * Manage multiple beneficiaries * Update beneficiary details * Each beneficiary undergoes details validation: * **Bank transfers**: Account and bank details validation (if supported by payout partner) * **Mobile money**: Phone number validation (if supported by payout partner) Explore beneficiary management and validation. #### Corridors A corridor represents a **send-receive country pair** with specific: * Supported payout methods * Transaction limits * Processing times * Fee structures * Regulatory requirements View all supported corridors and their specifications. ### Compliance & Security We operate a **tiered KYC system** as well as a dynamic compliance system to balance sender experience with regulatory requirements as well as custom client integrations: #### AML/CFT Screening Every transaction is screened against: * **Sanctions lists** - OFAC, EU, UN consolidated lists * **PEP databases** - Politically exposed persons screening * **Transaction patterns** - Unusual activity detection * **Risk scoring** - Dynamic risk assessment Deep dive into compliance requirements and processes. ### Integration Quick Start Before you begin: Contact our team to receive your sandbox API keys and base URL. Familiarize yourself with our [API Reference](/api/introduction). Read through the [Process Flows](/remittance/process-flows) to understand the complete senders journey. Explore all available endpoints with request/response examples. ### Supported Payout Methods #### Bank Transfer Direct deposit to beneficiary's bank account via SWIFT or alternative rails. * **Settlement Time**: Instant * **Coverage**: 100+ countries * **Best for**: Large amounts, regular recipients #### Mobile Money Instant transfer to mobile wallet providers like MTN, Airtel, Vodafone, and more. * **Settlement**: Instant -1hr * **Coverage**: Africa, Asia, Latin America * **Best for**: Unbanked recipients, urgent transfers #### Cash Pickup Beneficiary collects cash at partner agent locations. * **Settlement**: Instant availability * **Coverage**: 200+ countries via partner networks * **Best for**: Recipients without bank accounts or mobile wallets Detailed settlement options and requirements. ### Fee Structure Our transparent fee structure includes: * Transfer Fees * Payment Method Fees * FX Margin View detailed fee structure for all corridors. ### Testing & Sandbox We provide a full-featured sandbox environment for testing: * **Sandbox URL**: `https://{domain}.fincode.software` * **Test credentials**: Provided upon registration * **Mock payment gateway**: Simulate successful/failed payments * **No real money**: All transactions are simulated Use the sandbox to test all flows, edge cases, and error handling before going live. ### Integration Models We support two primary integration approaches to fit your business needs: ### End-to-End Integration Build the complete remittance experience within your application, managing the entire user journey from registration to transaction completion. **Flow**: 1. User onboarding and registration 2. KYC verification 3. Transaction initiation 4. Payment collection 5. Compliance screening 6. Settlement **Documentation**: * [Complete Process Flows](/remittance/process-flows) * [User Management APIs](/api/users/create-customer) * [Authentication](/api/auth/login) ### Complete Transaction Journey The diagram below shows the end-to-end flow for **full customer journey** integration: ```mermaid theme={null} graph TD A[Download App] --> B[Sign Up] B --> C[Login] C --> D{KYC Required?} D -->|Yes| E[Complete KYC] D -->|No| F[Dashboard] E --> G{CRA Forms?} G -->|Yes| H[Complete CRA Forms] G -->|No| F H --> F F --> I[Initiate Transaction] I --> J[Select Transaction Type] J --> K[Choose Destination Country] K --> L[Enter Amount] L --> M[Get Quote with FX Rate] M --> N{Beneficiary Exists?} N -->|Yes| O[Select Beneficiary] N -->|No| P[Create New Beneficiary] O --> Q[Review Transaction] P --> Q Q --> R[Make Payment] R --> S[Compliance Check] S --> T[FX Conversion] T --> U[Disbursement] U --> V[Transaction Complete] style A fill:#e1f5ff style V fill:#d4edda style S fill:#fff3cd ``` ### Direct Transaction Submission If you already manage your own customers and KYC processes, you can submit transactions directly with customer and beneficiary details included. **Flow**: ``` Your System (Customer Management) ↓ Submit Transaction (with customer + beneficiary data) ↓ Our System (Compliance + Settlement) ↓ Transaction Complete ``` **What You Provide**: * Customer information (name, email, phone, address) * Beneficiary details (name, account/phone, country) * Transaction amount and currency **What We Handle**: * Payment routing * Settlement to beneficiary * Status updates via webhooks For **transaction-only integration**, your flow starts at the "Compliance Check" stage, with customer and beneficiary data already provided: ```mermaid theme={null} graph TD A[Your System] --> B[Submit Transaction with Customer Data] B --> C[Our System: Compliance Check] C --> D[Disbursement] D --> E[Transaction Complete] E --> F[Webhook Notification to Your System] style A fill:#e1f5ff style F fill:#d4edda style C fill:#fff3cd ``` Contact our integration team to enable direct transaction submission for your account. ## Next Steps Visualize the complete transaction journey with detailed diagrams Understand transaction states and transitions Explore supported countries and their specifications Jump into the API documentation and begin building # Process Flow Source: https://docs.fincode.technology/remittance/process-flows This guide provides comprehensive visual diagrams and step-by-step explanations of the complete remittance flow, from user onboarding through transaction settlement. The complete journey has **4 main phases**: Onboarding, Transaction Initiation, Payment & Processing, and Post-Transaction. ### Phase 1: Sender Onboarding & Authentication #### 1.1 Sender Registration The registration process creates a new sender account with required personal information. ```mermaid theme={null} sequenceDiagram participant Sender participant App participant API participant Email Service participant Admin Sender->>App: Download from App Store Sender->>App: Click "Register" App->>Sender: Show registration form Sender->>App: Submit details App->>API: POST /create-customer API->>API: Validate data API->>API: Create sender account API->>Email Service: Send welcome email Email Service-->>Sender: Welcome email API->>Admin: Notify new registration API-->>App: Registration successful App-->>Sender: Navigate to login ``` Go to create customer endpoint. #### Sender Experience Flow Sender downloads the app from PlayStore (Android) or App Store (iOS) Sender taps "Signup" on the welcome screen Sender completes the multi-step registration form with personal details Sender receives a welcome email with account confirmation Admin dashboard receives notification about the new registration for monitoring ### 1.2 Sender Login & Authentication Secure authentication using email and password with JWT token management. ```mermaid theme={null} sequenceDiagram participant Sender participant App participant API participant Auth Service Sender->>App: Launch app Sender->>App: Click "Login" App->>Sender: Show login form Sender->>App: Enter email & password App->>API: PUT /auth/login API->>Auth Service: Validate credentials Auth Service->>Auth Service: Check sender role Auth Service-->>API: Sender authenticated API->>API: Generate JWT tokens API-->>App: Return tokens + sender data App->>App: Store tokens securely App-->>Sender: Navigate to dashboard ``` Go to login endpoint. ### 1.3 KYC Verification Know Your Customer (KYC) verification is required before sender's can make transactions. ```mermaid theme={null} sequenceDiagram participant Sender participant App participant API participant KYC Service participant Compliance App->>API: Check KYC requirement API-->>App: KYC required App->>Sender: Show KYC form Sender->>App: Upload ID documents Sender->>App: Enter personal details App->>API: POST /submit-kyc-documents API->>KYC Service: Process documents KYC Service->>KYC Service: Extract data (OCR) KYC Service->>Compliance: Run checks Compliance->>Compliance: Verify identity Compliance->>Compliance: Sanctions screening Compliance-->>KYC Service: Verification result KYC Service-->>API: KYC status updated API-->>App: Verification complete App->>Sender: Send notification App-->>Sender: Navigate to dashboard ``` View available kyc requirements Submit KYC documents ### Required Documents * **Government-issued ID**: Passport, driver's license, or national ID card * **Selfie**: For liveness check and face matching ### Verification Process 1. Automated OCR extracts data from ID document 2. Face matching compares selfie with ID photo 3. Basic sanctions screening against global watchlists 4. Identity verification through third-party services **0-2 minutes** - Fully automated processing Tier 1 is ideal for senders who need to send smaller amounts quickly without extensive documentation. ### Required Documents * **Government-issued ID**: Same as Tier 1 * **Proof of address**: Utility bill, bank statement, or government letter (dated within 3 months) * **Selfie**: For liveness check ### Verification Process 1. All Tier 1 verification checks 2. Enhanced PEP (Politically Exposed Person) screening 3. Address verification and validation 4. Source of funds verification 5. Employment verification (if applicable) **0-1 hour** - Includes manual review for certain documents Tier 2 is required for senders who need to send larger amounts regularly. #### KYC Decision Flow ```mermaid theme={null} graph TD A[KYC Submission] --> B{Document Quality OK?} B -->|No| C[Request Re-upload] B -->|Yes| D[OCR Extraction] D --> E{Data Extracted?} E -->|No| F[Manual Review] E -->|Yes| G[Face Match] G --> H{Match Score > 85%?} H -->|No| F H -->|Yes| I[Sanctions Check] I --> J{Clean?} J -->|No| K[REJECTED] J -->|Yes| L[Identity Verification] L --> M{Verified?} M -->|No| F M -->|Yes| N[APPROVED] F --> O{Reviewable?} O -->|Yes| N O -->|No| K style N fill:#d4edda style K fill:#f8d7da style F fill:#fff3cd ``` *** ### 1.4 Customer Risk Assessment (CRA) CRA forms are optional forms for collecting additional user information for regulatory compliance and risk assessment. ```mermaid theme={null} sequenceDiagram participant Sender participant App participant API participant Compliance App->>API: Check for pending CRA forms API->>Compliance: Get required forms Compliance-->>API: Return form templates API-->>App: CRA forms required App->>Sender: Display dynamic form Sender->>App: Complete form fields App->>API: POST /cra-forms API->>Compliance: Store responses Compliance->>Compliance: Calculate risk score Compliance-->>API: Risk assessment complete API-->>App: Proceed to dashboard App-->>Sender: Dashboard loaded ``` Go to CRA form endpoint. #### When CRA Forms Are Required Required when transaction amount exceeds limit set for the first time. Transactions to countries with enhanced due diligence requirements. Annual or biennial reviews for active customers. When new regulations require additional information. #### Typical CRA Questions **Question**: Where does the money you're sending come from? **Options**: * Employment/Salary * Business income * Savings * Gift * Inheritance * Investment returns * Other (specify) **Question**: What is the purpose of this transfer? **Options**: * Family support * Education fees * Medical expenses * Business payment * Property purchase * Investment * Gift * Other (specify) **Question**: What is your relationship to the beneficiary? **Options**: * Family member (parent, sibling, spouse, child) * Friend * Business partner * Employee * Myself * Other (specify) **Question**: How often do you plan to send money? **Options**: * One-time only * Monthly * Quarterly * As needed * Weekly **Question**: What is your occupation and employer? **Fields**: * Occupation/Job title * Employer name * Industry sector ## Phase 2: Transaction Initiation ### 2.1 Dashboard & Send Money The dashboard is the central hub for all remittance activities. ```mermaid theme={null} graph LR A[Dashboard] --> B[Recent Transactions] A --> C[Send Money] A --> D[Transaction History] A --> E[Beneficiaries] A --> F[Profile] C --> G[Bank Transfer] C --> H[Mobile Money] C --> I[Cash Pickup] style A fill:#e1f5ff style C fill:#fff3cd ``` #### Dashboard Features One-tap access to start a new transaction. Last 5 transactions with status indicators. Current verification tier and limits. Quick access to frequent recipients. Remaining daily/monthly limits. Live rates for popular corridors. ### 2.2 Transaction Type Selection Senders choose from three or more primary transaction types based on beneficiary preferences. ### Overview Direct deposit into beneficiary's bank account using SWIFT or local banking rails. ### Sender Flow 1. Sender selects "Bank Transfer" option 2. Choose destination country from list 3. Enter transfer amount 4. Get instant quote with FX rate ### Required Information * Account number or IBAN * SWIFT/BIC code (for international transfers) * Beneficiary full name (must match bank records) * Dynamic form details (if required & set by the backend) ### Settlement Time **Instant** ### Best For * Large transfer amounts * Regular recipients with bank accounts * Countries with strong banking infrastructure **API Endpoint**: [Create Transaction](/api/transactions/create-transaction) Bank transfers typically have the lowest fees for amounts over £500/\$750. ### Overview Instant transfer to mobile wallet providers like MTN, Airtel, Vodafone, M-Pesa, and more. ### Sender Flow 1. Sender selects "Mobile Money" option 2. Choose destination country 3. Select mobile network provider from dropdown 4. Enter transfer amount 5. Get instant quote ### Required Information * Mobile phone number of beneficiary * Mobile network provider name * Beneficiary full name (if validation not supported) ### Settlement Time **Instant to 1 hour** - Fastest delivery method ### Best For * Unbanked beneficiaries * Urgent transfers * African, Asian, and Latin American corridors * Small to medium amounts ### Supported Providers MTN, Airtel, Vodacom, Safaricom M-Pesa, Orange Money, Tigo bKash, Nagad, GCash, PayMaya, Wave Money Go to create transaction endpoint. Mobile money has daily limits imposed by mobile network operators (typically $500-$1000 per day). ### Overview Beneficiary collects physical cash at partner agent locations worldwide. ### Sender Flow 1. Sender selects "Cash Pickup" option 2. Choose destination country 3. Select pickup network partner 4. Enter transfer amount 5. Get instant quote ### Required Information * Beneficiary Phone number * Pickup unique code/secret ### Settlement Time **Instant availability** - Cash ready within minutes ### Best For * Beneficiaries without bank accounts or mobile money * Urgent cash needs * Rural areas with limited banking infrastructure * One-time transfers ### Pickup Process 1. Sender completes transaction and receives reference number 2. Beneficiary receives SMS with pickup code/PIN 3. Beneficiary visits agent location with: * Government-issued ID * Pickup code/PIN * Sender's name 4. Agent verifies identity and disburses cash ### Partner Networks * Ria * Remitly * MoneyGram * Western Union Go to create transaction endpoint. Cash pickup typically has higher fees (3-5%) but offers universal accessibility. Go to transaction types endpoint. ### 2.3 FX Quotation Flow Real-time exchange rate quotation with rate locking mechanism. ```mermaid theme={null} sequenceDiagram participant Sender participant App participant API participant FX Service participant Compliance participant Fee Engine Sender->>App: Enter send/receive amount Sender->>App: Select destination country App->>API: POST /call-quote API->>FX Service: Get live exchange rate FX Service-->>API: Current rate API->>Fee Engine: Calculate fees Fee Engine-->>API: Transfer fee + margins API->>Compliance: Check transaction limits Compliance-->>API: Within limits API->>API: Calculate total amounts API-->>App: Return quote breakdown App-->>Sender: Display quote Note over Sender,App: Quote valid realtime Sender->>App: Accept quote App->>API: POST /lock-rate API->>FX Service: Lock rate FX Service-->>API: Rate locked API-->>App: Proceed to beneficiary ``` Go to transaction quote endpoint. ### 2.4 Beneficiary Management Senders can save and manage beneficiaries for faster repeat transactions. ```mermaid theme={null} graph TD A[Select Beneficiary] --> B{Has Beneficiaries?} B -->|Yes| C[Show Beneficiary List] B -->|No| D[Create New Beneficiary] C --> E{Select Action} E -->|Select| F[Use Existing] E -->|New| D D --> G[Enter Details] G --> H[Validate Information] H --> I{Valid?} I -->|Yes| J[Sanctions Screening] I -->|No| G J --> K{Screening Passed?} K -->|Yes| L[Save Beneficiary] K -->|No| M[Cannot Add] L --> N[Proceed to Review] F --> N style B fill:#fff3cd style I fill:#fff3cd style K fill:#fff3cd ``` **API Endpoints**: View all saved beneficiaries endpoint. Create beneficiary endpoint. #### Create New Beneficiary Flow ```mermaid theme={null} sequenceDiagram participant Sender participant App participant API participant Validation Service participant Sanctions DB Sender->>App: Enter beneficiary details App->>API: POST /beneficiary-details API->>Validation Service: Validate account Validation Service->>Validation Service: Check bank/provider exists Validation Service->>Validation Service: Verify account format Validation Service->>Validation Service: Validate routing codes Validation Service-->>API: Validation result alt Account Valid API->>Sanctions DB: Screen beneficiary name Sanctions DB->>Sanctions DB: Check watchlists Sanctions DB-->>API: Screening result alt No Sanctions Match API->>API: Save beneficiary API-->>App: Beneficiary created App-->>Sender: Show success message else Sanctions Match API-->>App: Cannot add beneficiary App-->>Sender: Show compliance message end else Account Invalid API-->>App: Validation failed App-->>Sender: Show error & corrections end ``` #### Beneficiary Validation Rules ### Validation Checks * **Bank name**: Must exist in destination country * **Account number**: Format validation (e.g., 10 digits for Nigerian accounts) * **SWIFT/BIC code**: Valid code from SWIFT registry * **IBAN**: Checksum validation for IBAN countries * **Beneficiary name**: Minimum 3 characters, maximum 100 characters ### Example: UK Bank ```json theme={null} { "beneficiaryName": "John Smith", "bankName": "Barclays Bank UK", "accountNumber": "12345678", "sortCode": "20-00-00", "country": "GB" } ``` ### Example: Nigerian Bank ```json theme={null} { "beneficiaryName": "Chinwe Okafor", "bankName": "Guaranty Trust Bank", "accountNumber": "0123456789", "country": "NG" } ``` ### Validation Checks * **Phone number**: International format validation * **Provider**: Must be active in destination country * **Number registration**: Some providers verify if number is registered * **Beneficiary name**: Must match registered mobile money account ### Example: Kenya M-Pesa ```json theme={null} { "beneficiaryName": "James Mwangi", "phoneNumber": "+254712345678", "provider": "Safaricom M-Pesa", "country": "KE" } ``` ### Example: Ghana MTN ```json theme={null} { "beneficiaryName": "Akua Mensah", "phoneNumber": "+233201234567", "provider": "MTN Mobile Money", "country": "GH" } ``` ### Validation Checks * **Full name**: At least first and last name * **Phone number**: Valid international format * **Pickup location**: Valid city in destination country * **ID requirement**: Beneficiary must have government ID ### Example ```json theme={null} { "beneficiaryName": "Maria Rodriguez", "phoneNumber": "+521234567890", "pickupLocation": "Mexico City", "pickupNetwork": "Elektra", "country": "MX" } ``` For cash pickup, beneficiary name must **exactly match** their government-issued ID. ## Phase 3: Payment & Processing ### 3.1 Transaction Review Before payment, senders review all transaction details for accuracy. #### Review Screen Components * **Send amount**: Amount sender is sending * **Send currency**: Source currency (GBP, USD, EUR) * **Exchange rate**: FX rate * **Rate validity**: Countdown timer (10 minutes) * **Transfer fee**: Platform fee * **Payment method fee**: Card fee if applicable * **Total to pay**: Final amount to be charged * **Fee breakdown**: * Transfer fee * Payment method fee * Exchange rate margin * Other fees (if any) * **Receive amount**: Amount beneficiary gets * **Receive currency**: Destination currency * **Delivery method**: Bank/Mobile/Cash * **Estimated delivery**: Time to complete * **Recipient name**: Full name * **Delivery details**: Account/phone number * **Destination country**: Country flag and name * **Transaction type**: Visual indicator ### 3.2 Payment Processing Secure payment through card or open banking with 3D Secure authentication. ```mermaid theme={null} sequenceDiagram participant Sender participant App participant API participant Payment Gateway participant Bank participant System Sender->>App: Confirm transaction App->>API: POST /create-transaction API->>API: Create transaction record API-->>App: Transaction ID (WAITING_TO_PAY) App->>Sender: Choose payment method Sender->>App: Select card/open banking App->>Payment Gateway: Initialize payment Payment Gateway->>Payment Gateway: Create session Payment Gateway-->>App: Payment session URL App-->>Sender: Redirect to payment page alt Card Payment Sender->>Payment Gateway: Enter card details Payment Gateway->>Bank: Request 3DS authentication Bank-->>Sender: OTP/2FA prompt Sender->>Bank: Complete authentication Bank->>Bank: Validate OTP Bank-->>Payment Gateway: Auth successful Payment Gateway->>Payment Gateway: Charge card else Open Banking Sender->>Payment Gateway: Select bank Payment Gateway-->>Sender: Redirect to bank login Sender->>Bank: Login with credentials Bank-->>Sender: Show payment authorization Sender->>Bank: Authorize payment Bank->>Bank: Process payment Bank-->>Payment Gateway: Payment authorized end Payment Gateway->>Payment Gateway: Process payment Payment Gateway-->>API: Webhook: Payment successful API->>System: Update status to VERIFYING API->>System: Trigger compliance checks Payment Gateway-->>App: Redirect with success App-->>Sender: Show success screen App-->>Sender: Display transaction reference ``` *** View detailed integration steps for Card and Open Banking payments. ### 3.3 Compliance Screening All transactions undergo automated compliance checks before processing. ```mermaid theme={null} sequenceDiagram participant System participant Compliance API participant AML Service participant Sanctions DB participant Risk Engine System->>Compliance API: Screen transaction Compliance API->>AML Service: Check AML/CFT rules AML Service->>AML Service: Analyze transaction patterns AML Service->>AML Service: Check velocity limits AML Service->>AML Service: Review transaction history AML Service-->>Compliance API: AML result Compliance API->>Sanctions DB: Screen all parties Sanctions DB->>Sanctions DB: Check OFAC lists Sanctions DB->>Sanctions DB: Check EU sanctions Sanctions DB->>Sanctions DB: Check UN lists Sanctions DB-->>Compliance API: No matches found Compliance API->>Risk Engine: Calculate risk score Risk Engine->>Risk Engine: Assess country risk Risk Engine->>Risk Engine: Evaluate customer profile Risk Engine->>Risk Engine: Analyze transaction size Risk Engine-->>Compliance API: Risk score: LOW alt Low Risk - Approved Compliance API-->>System: STATUS: APPROVED System->>System: Proceed to FX conversion else Medium Risk - Flagged Compliance API-->>System: STATUS: FLAGGED System->>System: Hold for manual review System->>System: Notify compliance team Note over System: Transaction paused (1-24 hours) else High Risk - Rejected Compliance API-->>System: STATUS: REJECTED System->>System: Cancel transaction System->>System: Initiate refund process System->>System: Send rejection notice to customer end ``` #### Screening Checks Performed ### Anti-Money Laundering & Counter-Terrorism Financing **Transaction Pattern Analysis**: * Unusual transaction amounts * Frequency of transfers * Multiple small transactions (structuring) * Sudden changes in behavior * Round-number transactions **Velocity Checks**: * Daily transaction count * Weekly transaction volume * Monthly cumulative amount * Same-day repeat transactions **Historical Analysis**: * Customer transaction history * Failed transaction attempts * Previous flagged transactions * Account age vs. transaction size Transactions showing signs of money laundering (e.g., multiple small transfers to avoid limits) are automatically flagged. ### Global Watchlist Checks **Lists Checked**: * **OFAC** (US Office of Foreign Assets Control) * **EU Sanctions List** * **UN Consolidated List** * **UK HM Treasury** * **National sanctions lists** (per jurisdiction) **Entities Screened**: * Sender (customer) * Beneficiary * Sender's country * Beneficiary's country * Financial institutions involved **Matching Algorithm**: * Exact name matches * Fuzzy matching (90%+ similarity) * Alias and known-as names * Date of birth verification * Address matching Even partial matches (80%+) trigger manual review to prevent false positives. ### Politically Exposed Persons **Categories**: * **Tier 1 PEPs**: Heads of state, ministers, judges * **Tier 2 PEPs**: Senior government officials * **Tier 3 PEPs**: Close associates and family members * **Former PEPs**: Individuals who held positions in past 12-18 months **Enhanced Due Diligence**: * Source of wealth verification * Purpose of transaction scrutiny * Relationship to beneficiary * Country risk assessment * Additional documentation requirements **Databases Used**: * World-Check (Refinitiv) * Dow Jones Risk & Compliance * LexisNexis * Local PEP databases PEP transactions aren't rejected automatically but require enhanced due diligence. ### Dynamic Risk Assessment **Risk Score Outcomes**: * **0-30**: Low risk → Auto-approve * **31-60**: Medium risk → Flag for review * **61-100**: High risk → Reject or enhanced review **Country Risk Classification**: * **Low**: UK, US, EU, Canada, Australia * **Medium**: Most Asian, Latin American countries * **High**: FATF blacklisted or sanctioned countries Regular customers with consistent transaction patterns receive better risk scores over time. #### Compliance Decision Matrix ```mermaid theme={null} graph TD A[Transaction Submitted] --> B{Sanctions Match?} B -->|Yes| C[REJECT - Refund] B -->|No| D{AML Flags?} D -->|Severe| C D -->|Minor| E{Calculate Risk Score} D -->|None| E E --> F{Risk Level?} F -->|Low 0-30| G[AUTO-APPROVE] F -->|Medium 31-60| H[MANUAL REVIEW] F -->|High 61-100| I{PEP?} I -->|Yes| J[ENHANCED DD] I -->|No| C H --> K{Reviewer Decision} K -->|Approve| G K -->|Reject| C J --> L{EDD Complete?} L -->|Pass| G L -->|Fail| C style G fill:#d4edda style C fill:#f8d7da style H fill:#fff3cd style J fill:#fff3cd ``` *** ### 3.4 FX Conversion & Settlement Once compliance checks pass, the system converts currency and initiates payout. ```mermaid theme={null} sequenceDiagram participant System participant FX Service participant Settlement API participant Partner Network participant Beneficiary participant Notifications System->>FX Service: Convert at locked rate FX Service->>FX Service: Apply exchange rate FX Service->>FX Service: Deduct FX margin FX Service-->>System: Conversion complete System->>System: Update status to PAID System->>Settlement API: Initiate payout request Settlement API->>Settlement API: Select optimal route Settlement API->>Partner Network: Transfer funds alt Bank Transfer Partner Network->>Partner Network: Initiate SWIFT/Local transfer Partner Network->>Partner Network: Process through banking rails Partner Network-->>Beneficiary: Credit bank account Note over Partner Network,Beneficiary: 1-24 hours else Mobile Money Partner Network->>Partner Network: Call mobile provider API Partner Network->>Partner Network: Verify recipient number Partner Network-->>Beneficiary: Credit mobile wallet Note over Partner Network,Beneficiary: Instant - 1 hour else Cash Pickup Partner Network->>Partner Network: Generate unique PIN Partner Network->>Partner Network: Activate at agent locations Partner Network-->>Beneficiary: SMS with PIN code Note over Partner Network,Beneficiary: Instant availability end Beneficiary-->>Partner Network: Acknowledge receipt Partner Network-->>Settlement API: Confirmation received Settlement API-->>System: Status: COMPLETED System->>Notifications: Trigger notifications Notifications-->>Beneficiary: SMS: Funds received Notifications-->>System: Email: Transaction receipt Notifications-->>System: Push: Transaction complete ``` #### Settlement Times by Method | Payout Method | Typical Time | Fastest | Latest | Availability | | - | - | - | - | - | | **Bank Transfer** | Instant | Instant | 30secs | 24/7 | | **Mobile Money** | Instant | Instant | 1 hour | 24/7 | | **Cash Pickup** | Instant | Instant | N/A | Agent hours | ## Phase 4: Post-Transaction ### 4.1 Status Tracking Transactions move through defined states from creation to completion. ```mermaid theme={null} stateDiagram-v2 [*] --> WaitingToPay: Transaction Created WaitingToPay --> Verifying: Payment Received WaitingToPay --> Cancelled: Sender Cancelled WaitingToPay --> Expired: Rate/Payment Timeout Verifying --> Paid: Compliance Approved Verifying --> PendingRefund: Compliance Rejected Verifying --> FailedToDeliver: Initial Delivery Failed Paid --> [*]: Success FailedToDeliver --> Paid: Retry Successful FailedToDeliver --> PendingRefund: Max Retries Exceeded PendingRefund --> Refunded: Refund Processed Refunded --> [*]: Complete Cancelled --> [*]: Complete Expired --> [*]: Complete ``` *** Go to transaction history endpoint. #### Transaction Status Definitions **Description**: Transaction created but payment not yet received **Sender Actions**: * Complete payment via card or open banking * Cancel transaction **Next States**: * `VERIFYING` - Payment received * `CANCELLED` - Sender cancelled * `EXPIRED` - Quote/payment timeout **Description**: Payment received, undergoing compliance checks **System Actions**: * AML/CFT screening * Sanctions checking * Risk assessment * PEP screening (if applicable) **Next States**: * `PAID` - All checks passed * `PENDING_REFUND` - Compliance rejected * `FAILED_TO_DELIVER` - Delivery issues **Description**: Transaction completed successfully, funds delivered **System Actions**: * FX conversion executed * Funds disbursed to beneficiary * Confirmations sent **Notifications Sent**: * Email receipt to sender * SMS to beneficiary * Push notification (if enabled) **Final State**: Transaction complete ✓ **Description**: Delivery attempt failed (wrong account, network issues, etc.) **Common Causes**: * Invalid account number * Inactive mobile money account * Bank account closed * Network timeout **System Actions**: * Transaction retry (if activated) * Notify compliance team * Contact customer for corrections **Next States**: * `PAID` - Retry successful * `PENDING_REFUND` **Description**: Refund initiated, processing back to sender **Triggers**: * Compliance rejection * Delivery failure (max retries) * Customer request (within refund window) **Next State**: `REFUNDED` - Refund complete **Description**: Funds returned to sender's payment method **Details**: * Full refund (including fees) * Returns to original payment method * Refund confirmation sent **Final State**: Transaction complete (refunded) **Description**: Transaction cancelled before payment **Triggers**: * Sender cancelled during payment * Sender didn't complete payment **No Charges**: No funds were debited **Final State**: Transaction complete (cancelled) **Description**: Payment window expired **Causes**: * Payment not completed in time **Final State**: Transaction complete (expired) ## API Integration Checklist Follow these steps to integrate the complete remittance flow: ### Implement Sender Registration & Authentication **Testing Checklist**: * [ ] Sender can register with valid details * [ ] Email validation works * [ ] Password strength requirements enforced before any data encryption * [ ] Login returns valid JWT tokens * [ ] KYC document upload successful * [ ] CRA form submission works View detailed sender management endpoints ### Build Quote, Beneficiary & Transaction Creation **Testing Checklist**: * [ ] Quote returns accurate FX rates * [ ] Beneficiary validation catches errors * [ ] Transaction creation returns correct status * [ ] Multiple payout methods available View transaction API documentation ### Connect Payment Gateway **Implementation**: * Integrate card payment provider (Trustpayment/Paycross) * Implement open banking (Volume/Volt) * Handle 3DS authentication flow * Implement payment webhooks **Testing Checklist**: * [ ] Card payments process successfully * [ ] 3DS authentication works * [ ] Open banking redirects correctly * [ ] Payment webhooks received * [ ] Failed payments handled gracefully Detailed payment integration guide ### Implement Transaction Monitoring **Testing Checklist**: * [ ] Status updates reflect in real-time * [ ] Webhooks received and processed * [ ] All transaction states handled * [ ] Error states trigger appropriate UI Configure webhook endpoints ### Comprehensive Testing in Sandbox **Testing Checklist**: * [ ] All flows tested in sandbox * [ ] Error handling implemented * [ ] Sender feedback messages clear * [ ] Transaction receipts generated * [ ] Notifications working Complete testing documentation ## Next Steps Ready to integrate? Head to the API documentation and start building your remittance application. # Transaction Lifecycle Source: https://docs.fincode.technology/remittance/transactions Understand transaction states, transitions, and what triggers each status change. Every remittance transaction moves through a series of well-defined states from creation to completion. Understanding these states helps you build robust integrations and provide clear user feedback. ```mermaid theme={null} stateDiagram-v2 [*] --> WaitingToPay: Transaction Created WaitingToPay --> Verifying: Payment Received WaitingToPay --> Cancelled: User Cancelled WaitingToPay --> Expired: Timeout (10 min) Verifying --> Paid: Compliance Passed Verifying --> PendingRefund: Compliance Failed Verifying --> FailedToDeliver: Delivery Issue FailedToDeliver --> Paid: Retry Successful FailedToDeliver --> PendingRefund: Max Retries PendingRefund --> Refunded: Refund Complete Paid --> [*] Refunded --> [*] Cancelled --> [*] Expired --> [*] note right of Verifying AML/Sanctions screening typically 1-5 minutes end note note right of FailedToDeliver Automatic retry up to 3 attempts end note ``` ### Active States **Description**: Transaction created, awaiting payment from user **What Happens**: * Transaction reference generated * User redirected to payment page * Timer starts for quote validity **User Actions Available**: * Complete payment via card or open banking * Cancel the transaction * View transaction details **Next Possible States**: * `VERIFYING` - Payment successfully received * `CANCELLED` - User cancelled before payment * `EXPIRED` - Payment not completed within 10 minutes **Description**: Payment received, undergoing compliance checks **What Happens**: * AML/CFT screening initiated * Sanctions list checking * Risk score calculation * PEP screening (if applicable) * Transaction pattern analysis **System Actions**: * Automated compliance checks run * Manual review triggered if flagged * Compliance team notified (if needed) **Next Possible States**: * `PAID` - All checks passed, funds disbursed * `PENDING_REFUND` - Compliance or payment after transaction expiration * `FAILED_TO_DELIVER` - Delivery issues detected Most transactions (95%+) pass automated checks and move to PAID within 0-2 minutes. **Description**: Delivery attempt failed, automatic retry in progress **Common Causes**: * Invalid or closed bank account * Inactive mobile money account * Network timeout or provider downtime * Incorrect account details * Beneficiary name mismatch **System Actions**: * Exponential backoff between retries * Notify compliance team after 2nd failure * Contact user for corrections if needed **Next Possible States**: * `PAID` - Retry successful * `PENDING_REFUND` Contact your customer to verify beneficiary details if this status persists. **Description**: Refund initiated, processing back to sender **Triggers**: * Compliance rejection (AML/sanctions) * Delivery failure after max retries * Customer dispute (within refund window) * Technical error requiring reversal **What Happens**: * Refund request submitted to payment processor * Original payment method receives credit * Refund notification sent to user * Transaction marked for closure **Refund Amount**: * Full transaction amount (send amount) * All fees included * Same payment method as original **Next Possible State**: * `REFUNDED` - Refund completed successfully ## State Transition Triggers Understanding what causes state changes helps you build better error handling. ### Payment-Related Transitions | From State | To State | Trigger | Action Required | | - | - | - | - | | `WAITING_TO_PAY` | `VERIFYING` | Payment successful | Automatic | | `WAITING_TO_PAY` | `CANCELLED` | User cancelled | None | | `WAITING_TO_PAY` | `EXPIRED` | 10 min timeout | Request new quote | ### Compliance-Related Transitions | From State | To State | Trigger | Action Required | | - | - | - | - | | `VERIFYING` | `PAID` | All checks passed | None - Automatic | | `VERIFYING` | `PENDING_REFUND` | Compliance/Payment failed | Contact support | | `VERIFYING` | `FAILED_TO_DELIVER` | Delivery issue | Check beneficiary details | ### Refund Transitions | From State | To State | Trigger | Action Required | | - | - | - | - | | `PENDING_REFUND` | `REFUNDED` | Refund processed | Automatic | Learn how to set up webhooks for real-time updates ## Common Scenarios ### Scenario 1: Successful Transaction ```mermaid theme={null} graph LR A[WAITING_TO_PAY] -->|Payment received| B[VERIFYING] B -->|Checks passed| C[PAID] style C fill:#d4edda ``` ### Scenario 2: Compliance Rejection ```mermaid theme={null} graph LR A[WAITING_TO_PAY] -->|Payment received| B[VERIFYING] B -->|Sanctions match/Payment failed| C[PENDING_REFUND] C -->|Refund processed| D[REFUNDED] style D fill:#f8d7da ``` ### Scenario 3: Delivery Failure with Recovery ```mermaid theme={null} graph LR A[WAITING_TO_PAY] -->|Payment received| B[VERIFYING] B -->|Checks passed| C[FAILED_TO_DELIVER] C -->|Retry successful| D[PAID] style D fill:#d4edda ``` ## API Reference View complete API documentation for tracking transaction status Learn how to create and validate beneficiaries ## Quote Calculator Integration You can easily integrate a Quote Calculator into your own website or dashboard using our ready-made widget. This handles flag updates, country selection, and real-time exchange rates automatically. ### Integration Guide Add the following code to your HTML page where you want the widget to appear: Place this `div` in your layout. You can customize the initial values using `data-` attributes. ```html theme={null}
```
Add this script tag at the bottom of your `` tag. ```html theme={null} ```
### Configuration Options Customize the widget behavior by adding these attributes to the container `div`: | Attribute | Description | Default | | :- | :- | :- | | `data-default-send-country` | ISO3 Code for the default sending country | `GBR` | | `data-default-receive-country` | ISO3 Code for the default receiving country | `NGA` | | `data-default-amount` | Initial amount for the "Send" field | `100` | | `data-button-text` | Text displayed on the main button | `Send Money Now` | | `data-button-color` | Color code for the action button | `#000000` | The widget is fully responsive and will adapt to the width of its parent container. For the best experience, place it in a column between 350px and 500px wide. To see the full usage guide, follow this link [https://fxquote-widget.vercel.app/index.html](https://fxquote-widget.vercel.app/index.html) # Overview Source: https://docs.fincode.technology/songhai-exchange/overview Songhai Exchange(SHE) is Fincode's payment switching platform that facilitates cross-border transactions, enabling services such as bank transfers, mobile money payments, and wallet management across multiple currencies and countries. ## Base URL All API requests for the staging environment should be sent to: ```bash theme={null} https://api.stag.songhaiexchange.io ``` ## Authentication The API uses **OAuth2** for security. 1. **Generate Token**: Call the `POST /oauth/token` endpoint using Basic Authentication (Client ID and Secret) along with your username and password. 2. **Make Requests**: Use the returned `access_token` as a Bearer token in the `Authorization` header for all protected endpoints. ```http theme={null} Authorization: Bearer ``` ## Transaction Reference (PCN) Every transaction is identified by a unique **Reference Code** (often referred to as PCN). This code is generated by you (the partner) and must be unique for every request. It is used to: * Track the status of a transaction. * Reconcile payments. ## Reference Data ### Transaction Types Use these values for the `transaction_type` field. | Value | Description | | :- | :- | | `AIRTIME_TOPUP` | Airtime Top-up | | `ACCOUNTPAYMENT` | Bank Transfer | | `ACCOUNTPAYMENT_DEBIT_CARD` | Debit Card | | `ACCOUNTPAYMENT_CREDIT_CARD` | Credit Card | | `CASHPICKUP` | Cash Pickup | | `CURRENCY_CONVERTER` | Bureau de Change | | `CRYPTO_CURRENCY` | Cryptocurrency | | `BILL_PAYMENT` | Bill Payment | | `WALLET` | Wallet | | `MERCHANT_PRODUCT` | Merchant Product | | `MOBILE_MONEY` | Mobile Money | | `MERCHANT_PAYMENT` | Merchant Payment | ### Transaction Purposes Use these values for the `transaction_purpose` field. | Value | Description | | :- | :- | | `FAMILY_SUPPORT` | Family support | | `EDUCATION` | Education | | `GIFT_AND_DONATION` | Gift and other donations | | `MEDICAL_TREATMENT` | Medical treatment | | `MAINTENANCE_EXPENSES` | Maintenance or other expenses | | `TRAVEL` | Travel | | `SMALL_VALUE_REMITTANCE` | Small value remittance | | `LIBERALIZED_REMITTANCE` | Liberalized remittance | | `OTHER` | Other purposes | ### Beneficiary Relationships Common values for `beneficiaryRelationship`: `FRIENDS`, `PARENTS`, `RELATIVES`, `SPOUSE`, `SIBLING`, `SELF`, `BUSINESS_PARTNER`, etc. ### Document Types Documents required for KYC/Compliance. | Value | | :- | | Passport | | National Id | | Driving License | | Voter’s card | | Proof of Address | | Customer declaration form | | Certificate of Incorporation | | ... (and others) | ### Response Statuses The lifecycle status of a transaction. | Status | Description | Lifecycle | | :- | :- | :- | | `SUCCESS` | Instruction successfully received. | Incomplete | | `PAID` | Successfully paid out to beneficiary. | Completed | | `FAILED` | Processed but unsuccessful. | Completed | | `PENDING` | Sent to beneficiary bank, awaiting confirmation. | Incomplete | | `READY_TO_CALL` | Queued to be sent to beneficiary bank. | Incomplete | | `PROCESSING` | Queued for processing. | Incomplete | | `CANCEL` | Instruction canceled. | Completed | | `ERROR` | Technical issue occurred. | Completed | ### Response Codes Specific error or success codes returned in `msg_code`. | Code | Status | Description | | :- | :- | :- | | `00` | PAID | Paid successfully | | `0000` | PENDING | Awaiting processing | | `0001` | FAILED | Invalid Bank Account Number | | `0002` | FAILED | Recipient Contact Details Invalid | | `0005` | FAILED | Invalid Bank Code | | `0030` | FAILED | Insufficient Funds | | `0042` | PENDING | Ready to Call (Queued) | | `50004` | FAILED | Unknown Error / Transaction Failed | ### HTTP Status Codes **Client Errors** | Code | Description | | :- | :- | | `400` | Bad Request | | `401` | Unauthorized | | `403` | Forbidden | | `404` | Not Found | | `429` | Too Many Requests (implied) | **Server Errors** | Code | Description | | :- | :- | | `500` | Internal Server Error | | `502` | Bad Gateway | | `503` | Service Unavailable | | `504` | Gateway Timeout |