Product Setup
Civil Servant Product Setup Guide (Ndasenda payroll deduction)
This guide configures a loan product for civil servants repaid by payroll deduction through Ndasenda — Zimbabwe’s payroll-deduction platform. The workflow verifies the borrower’s national ID against Ndasenda during KYC and registers the repayment mandate automatically once loan terms are set.
Audience: tenant administrators and lending operations.
Overview of the flow
Application → documents → Ndasenda ID check → employer/credit → offer accepted
→ Ndasenda mandate registered → final approval → origination
→ disbursement (NetOne B2C intent or manual) → servicing
→ payroll deduction remits repayments (plus optional NetOne self-pay)
Two integration gates do the provider work inside origination; disbursement and repayments run as payment intents afterwards. Nothing provider-specific is hardcoded — the same Ndasenda connection serves every product that needs it.
Step 1: Ndasenda prerequisites
Before configuring anything in Hiana Loans, obtain from Ndasenda:
- API credentials —
usernameandpasswordfor the OAuth token endpoint. - Security token — the static
securityTokensent in request bodies. - Deduction code — the employer/paymaster deduction code for your mandates.
- Base URL (and the token URL only if Ndasenda mounts OAuth somewhere other than
{base}/connect/token).
For each borrower, the mandate record needs:
- National ID number — on the borrower’s individual record.
- EC number and payroll number — on the borrower’s current employment record (fields added by migration
000268). Capture them at intake or on the borrower profile; application custom fields with the same keys override the record per application. - Linked employment — the borrower’s current employment must reference the employer, matching the employer-backed product prerequisites.
Step 2: Create the Ndasenda shared connection
Admin → Shared Integrations → New connection → adapter: Ndasenda direct
| Field | Value |
|---|---|
| Base URL | Ndasenda API base URL |
| Token URL | Leave blank unless Ndasenda gave you a different OAuth endpoint |
| Deduction code | The deduction code issued for your mandates |
| Username / Password | OAuth credentials |
| Security token | Static token from Ndasenda |
Save once — the connection is tenant-wide and reusable across products. Credentials are encrypted and write-only.
Step 3: Create the product
Admin → Loan Products → Create Product — name, currency, amount/term ranges, monthly repayment frequency to match the payroll cycle. Then work through the standard configuration tabs (documents, guarantor/MOU, credit risk, affordability) as in the employer-backed guide.
Step 4: Workflow with Ndasenda integration gates
Product Configuration → Workflow. Two steps of type Integration carry the provider work; the rest is the standard origination sequence.
| Order | Step key | Step type | Purpose |
|---|---|---|---|
| … | document_upload / document_review / kyc_verification | standard | as per the employer-backed baseline |
| 4 | ndasenda_id_check | INTEGRATION | Verify the national ID against Ndasenda IDChecks |
| … | fraud_screening, employer_approval, credit_check, underwriting, offer_proposal | standard | as per the baseline |
| 9 | offer_acceptance | OFFER_ACCEPTANCE | terms agreed — the proposal’s installment now exists |
| 10 | mandate_registration | INTEGRATION | Register the payroll deduction mandate |
| 11 | consent_capture, agreement_generation | standard | — |
| 12 | approval | APPROVAL | final internal approval |
Why the mandate sits after offer_acceptance: the default mandate record uses the active proposal’s installment as the deduction amount and the requested term as the mandate end date. Registering earlier would guess at an amount that underwriting may still change.
Step 5: Integration requirements
Product Configuration → Integrations — one requirement per gate step:
| Workflow type | Step key | Capability | Provider | Required |
|---|---|---|---|---|
LOAN_APPLICATION | ndasenda_id_check | IDENTITY_VERIFICATION | your Ndasenda connection | ✓ |
LOAN_APPLICATION | mandate_registration | MANDATE_REGISTRATION | your Ndasenda connection | ✓ |
Set Timeout (seconds) and Retry limit per gate (30s / 5 retries are sane starting points). Required gates block the step when the provider fails — leave required off only while piloting.
What the mandate submits
With no records override, the adapter builds one deduction record per mandate: type=NEW, idNumber (spaces/dashes stripped), ecNumber, payrollNumber, name/surname from the borrower record, reference = application number, startDate = today, endDate = start + requested term (yyyyMMdd), amount = proposal installment in cents. The batch also carries recordsCount and totalAmount (= Σ record amount), which Ndasenda validates — these are computed automatically. To submit a custom batch (multiple records, different amounts or dates), put a records array in the application’s custom fields — it passes through verbatim. Optional payload keys: total_amount/total_due (whole obligation, decimal-major → record totalAmount cents) and ignore_errors = true (submit with ?ignoreErrors=true so one bad record doesn’t fail the batch).
Registration is commit-then-poll: the batch is submitted, committed, then polled until Ndasenda’s response batch arrives. A declined record fails the gate; a batch with no response yet keeps the task pending rather than duplicating the mandate.
Step 6: Disbursement — NetOne (or traditional)
Once the application is approved and originated, fund the loan:
- NetOne B2C to the borrower’s OneMoney wallet: create the disbursement (mobile-money method, wallet number), then Start provider transfer on the disbursement record —
POST /servicing/disbursements/{id}/intentwith the NetOne connection. The adapter resolves the recipient’s NetOne ID via the subscriber lookup, verifies the wallet is active and certified, then pays out. A confirmed provider result is what activates the loan. - Traditional: record a bank transfer/cash disbursement as usual — no provider intent needed.
Requires a NetOne shared connection (b2c_url, b2c_status_url, customer_lookup_url, and the NetOne credential set). notify_url is optional — status polling covers final results either way.
Step 7: Repayment channels
- Payroll deduction (primary): the registered mandate deducts the installment each payroll cycle; remitted amounts are recorded against the loan through the normal repayment capture/import. The mandate amount equals the proposal installment.
- NetOne self-pay (OneMoney C2B): for catch-up or ad-hoc payments — the loan’s payment rail form posts
POST /servicing/payments/intents{loan_id, provider_id, amount, currency, mobile_number}. NetOne USSD-pushes that number; the payer approves by PIN. Any Zimbabwean NetOne number works — the payer need not be the registered borrower. Non-NetOne or inactive numbers are rejected before a request is sent (format check + subscriber lookup). - Traditional: cash, bank transfer, or POS recorded through normal payment capture — unaffected by whether integrations are configured.
Step 8: Mandate cancellation on closure
When the loan closes — full payoff, early settlement, or write-off — the closure service finds the application's succeeded mandate registration and queues a MANDATE_CANCELLATION payment intent against the same Ndasenda connection. The intent submits a DELETE record carrying the same borrower identifiers (national ID, EC/payroll numbers) the NEW record was registered with, then marks succeeded on provider acceptance.
- Nothing to configure: the original registration's provider and payload are reused, and the idempotency key deduplicates re-closure attempts.
- The cancellation is durable and retried like any payment intent — check its status at
GET /servicing/payments/intents/{id}if needed. - Confirm Ndasenda has accepted the DELETE record before relying on deductions having stopped.
Pensioner loans (pension-scheme mandates)
The same Ndasenda integration covers pension-scheme borrowers — the adapter picks the deduction code by employment scheme:
- Borrower record — set
employment_type=PENSIONER(oremployment_status=RETIRED) and capturepension_number. Ndasenda carries the pension number inpayrollNumber; the adapter falls back topension_numberautomatically when no payroll number exists. - Connection settings — add
deduction_code_pensioneralongsidededuction_code_ssbon the shared Ndasenda connection. Resolution order: explicit payloaddeduction_code→deduction_code_pensioner(pensioner/retired borrowers) →deduction_code_ssb(other schemes) → defaultdeduction_code. - Product — a pensioner product reuses this whole guide unchanged; only the borrower population differs. Pension income can feed affordability via the
enable_pension_incomecredit-risk data source.
Signed mandate document (TY30)
Pensioner mandates require the signed TY30 mandate form; SSB mandates do not. The adapter attaches the document between batch creation and commit when the payload carries mandate_document_base64 (base64 file content) plus optional mandate_filename. The attach key is resolved from ec_number → pension_number → payroll_number → id_number.
A pensioner mandate submitted without the document is held as a draft batch (result status: AWAITING_ATTACHMENTS, batch id in the external reference) rather than committed — committing without the attachment parks it permanently. Re-running the registration with mandate_document_base64 in the payload attaches the file, commits the held batch, and resumes polling. SSB registrations skip the attachment entirely and commit immediately.
All servicing operations (waivers, top-up, delinquency pause, re-aging, maker-checker) apply equally — see the Loan Servicing Operations Guide.
Checklist
- Migration
000268applied; borrower employment record carries EC + payroll number - Ndasenda connection saved with
deduction_code, OAuth credentials, security token - Workflow published with
ndasenda_id_checkandmandate_registrationINTEGRATION steps - Integration requirements saved with matching step keys, capabilities, required flags
- (If NetOne disbursement/self-pay) NetOne connection with
b2c_url,b2c_status_url,c2b_url,c2b_status_url,customer_lookup_url - Rehearse end-to-end: application → ID check passes → offer accepted → mandate batch committed → disbursement intent confirms → deduction recorded on the loan