Integrations
Biller-Routed Provider Connections — Setup Guide
This guide explains how tenant provider connections work when they are routed through the Biller engine — collections, disbursements, and payroll-deduction feeds (Ndasenda, NetOne, and future providers) that execute on the billing service rather than inside Hiana.
The Two-Layer Model
Hiana product / feed worker
│ references a provider connection by provider_id
▼
Hiana provider connection ← routing only (Admin → Integrations)
│ biller_provider_key points at…
▼
Biller provider connection ← owns endpoints, settings, credentials
│ adapter_key selects…
▼
Biller protocol adapter ← executes the real provider calls
- Hiana owns routing. Its connection is a pointer: "executions for this provider go to biller connection X using adapter Y." It stores no credentials and no provider settings of its own.
- Biller owns protocol config. Base URL, deduction codes, feed intervals, and encrypted credentials live on the biller connection (
/tenants/{id}→ Money movement → Provider connections). - Products reference the hiana connection. Integration gates in a product's workflow pick the hiana provider; the execution is forwarded to biller.
Prerequisites
- The organization exists as a tenant in Biller with the same canonical UUID as the Auth Engine organization (provisioning is a platform-admin operation —
POST /api/v1/tenantson biller, or the biller admin UI). - The biller-routed connection is configured on Biller first — adapter, base URL, deduction/feed settings, credentials.
Step 1 — Configure the connection on Biller
In the Biller admin UI, open the tenant workspace → Provider connections → Add:
| Field | Example |
|---|---|
| Provider key | ndasenda |
| Display name | Ndasenda SSB |
| Adapter | ndasenda |
| Base URL | https://api.sandbox.deductions.ndasenda.co.zw |
| Deduction code | your employer deduction code |
| Feed poll interval | 3600 (enables the repayment import feed) |
| Credentials | username / password / security token |
Credentials are write-only and encrypted at rest — they can be rotated by re-entering, never viewed again.
Running multiple schemes: Ndasenda issues separate deduction codes per paymaster (SSB civil servants vs pensioners). Create one biller connection per scheme — e.g. ndasenda (SSB code) and ndasenda-pension (pension code) — same base URL and credentials, different deduction code.
Step 2 — Create the routing provider on Hiana
Admin → Integrations → Provider connections → Add provider connection:
| Field | What to enter |
|---|---|
| Provider key | A unique key for this routing entry — e.g. biller-ndasenda. It identifies the hiana-side provider. |
| Display name | e.g. Ndasenda via Biller |
| Adapter | biller |
| Protocol adapter | The adapter on biller that executes this provider — ndasenda, netone, … (required) |
| Biller provider key | The provider_key of the connection created in Step 1 — e.g. ndasenda. Leave blank to default to this connection's provider key. |
| Settings JSON | Leave {} — settings live on the biller connection; an empty object preserves them. |
| Secrets | None — the biller adapter exposes no secret fields; credentials stay on biller. |
Save. The handler synchronizes the connection to biller and stores biller_connection_id back on the hiana provider. For a pension scheme, repeat with biller-ndasenda-pension → biller provider key ndasenda-pension.
What each system owns
| Hiana provider | Biller connection | |
|---|---|---|
| Purpose | routing reference | protocol execution |
| Provider key | biller-ndasenda | ndasenda |
| Settings | {} | base_url, deduction codes, feed interval |
| Credentials | none | username/password/security token |
Editing rules
- provider_key is the identity. Saving with a key that already exists edits that connection — the form warns when a key is in use. Two different schemes need two different keys.
- Saving the hiana provider never wipes biller config. An empty settings object is treated as "not managed here"; credentials are only replaced when secrets are explicitly provided.
- Renaming: the sync writes hiana's display name onto the biller connection — cosmetic only.
Step 3 — Reference it from products
In a product's workflow configuration, add INTEGRATION steps (e.g. ndasenda_id_check, mandate_registration) and select the routing provider (biller-ndasenda for civil-servant products, biller-ndasenda-pension for pensioner products). See CIVIL_SERVANT_PRODUCT_SETUP_GUIDE.md for the workflow steps themselves.
Executions are enqueued as integration executions in hiana, forwarded to biller, and resolved by the normal pending/poll lifecycle.
Step 4 — Repayment feeds
When a biller connection has a feed poll interval configured, biller polls the provider and stores normalized feed items. Hiana's repayment feed consumer pulls them per tenant and posts repayments against loans (matching borrowers by EC / payroll / pension number).
- The consumer only polls tenants with an enabled
billerprovider — enable/disable takes effect on the next sweep, no restart. GET /api/v1/money-movement/feeds/REPAYMENT_IMPORT/itemson biller returns 200 with an emptyitemsarray when the pipeline is healthy but idle.- Troubleshooting (401s, tenant-not-found, stuck cursors):
docs/repayment-feed-troubleshooting.md.
NetOne notify URL
The notify_url field is optional — the adapter auto-fills the built-in callback endpoint ({APP_BASE_URL}/api/v1/webhooks/netone) when neither the execution payload nor the connection setting provides one. NetOne posts the final order result there and the pending execution resolves immediately; status polling remains the fallback. Only set notify_url to route callbacks elsewhere.