DataCheck platform: how it works

A short guide to what the system does today, who can do what, and how money moves. Written for the owner and the team, not for developers only.

What it is

DataCheck sells identity and business checks to banks and Saccos. Organisations sign in to a dashboard, run checks, and pay for each one from a prepaid credit wallet. Resellers buy credit from DataCheck and sell checks to their own clients at their own price.

Today every check returns a sample result from the sandbox (fixed test answers). Results are marked "Sample result" on screen and stored with sample = true. No agency is called yet.

The checks

Check Agency Asks for Sample base price
KYC ID check by serial number Citizen KYC ID number, ID serial number KES 20
KYC ID check against phone number Citizen KYC ID number, phone number KES 20
BRS business check BRS Registration number KES 50
NTSA vehicle check NTSA Number plate KES 50
KRA PIN check KRA KRA PIN KES 30

The base prices are sample prices. The super admin changes them on the Pricing page.

Lawful purpose and consent: one declaration per organisation. Checks do not ask for a purpose or consent each time. Instead an owner or admin accepts a declaration once in Settings (what the organisation runs checks for, that it has consent or another lawful basis, and that it keeps results safe). It is stored with the time, the person and the version of the text, and checks (dashboard, bulk and API) are blocked until it is accepted. Older checks keep the purpose they were run with.

ID numbers, serial numbers, phone numbers and personal names are masked in history; the full sample answer is shown once, to the person who ran the check. While a check runs, a progress bar moves from 0 to 100% through four steps (verifying access, contacting agency, matching record, preparing result), for 1.5 to 3 seconds, and finishes when the answer arrives.

Modules

Module Screen What it does
Overview /dashboard Balance and how many checks it covers, latest checks, top-ups waiting for you, low-balance clients, recent activity. DataCheck and resellers also get analytics: checks over time, revenue and margin, top requests, outcomes, top clients and resellers, busiest days and hours, filtered by period, organisation and check
Products /dashboard/products/... A page per check: what it checks, what you enter and get back, your price, recent checks of that kind, and the form to run it
Bulk checks /dashboard/bulk Paste or upload a list (input template provided), see the cost first, run it in the background, view results in the protected viewer
Checks /dashboard/check, /dashboard/history Run a check (pick it from the menu); history with filters, masked details and CSV export; super admin can refund a check
Credit management /dashboard/credit Wallet balance, statement (every ledger entry), CSV, monthly statement CSV with opening and closing balance; super admin adds or removes credit with a reason
Transfers /dashboard/transfers Super admin sends credit to any reseller or client; a reseller sends credit to its own clients
Top-ups /dashboard/topups Request a top-up ("I paid KES X, reference Y"); approve or reject queue; CSV receipt for each approved top-up
Clients /dashboard/clients Super admin: every organisation, add clients and resellers, suspend, restore, make a client a reseller, custom prices. Reseller: its own clients
Pricing /dashboard/pricing Super admin sets base prices; reseller sets selling prices; clients see their own prices
Pull reports /dashboard/reports Checks, spend, reseller margin and DataCheck revenue by date range, organisation and check; CSV
User management /dashboard/users Add users with a role, change roles, deactivate, reset passwords, unlock locked accounts, reset two-step sign-in; permission table
Settings /dashboard/settings General: profile, password, appearance (System, Light or Dark theme), organisation details. Security: checklist, two-step sign-in, where you are signed in, and the organisation's security rules
Audit log /dashboard/audit Every sensitive action, who did it and when; CSV
API keys /dashboard/keys Keys for an organisation's own systems, with scopes; webhook address and signing secret
Security review /dashboard/security DataCheck staff: two-step sign-in coverage per organisation, locked accounts, failed sign-ins in the last 7 days; change any organisation's rules
Notifications Bell in the top bar Top-up decisions, credit received, low credit, security events
Ask DataCheck Search (Ctrl+K) and Ask (Ctrl+J) in the top bar Search pages, clients, checks, top-ups and this guide; answer how-to questions; prepare actions for you to confirm

Organisations

  • DataCheck (platform): the super admin and DataCheck staff. Sees and manages everything.
  • Reseller: buys credit from DataCheck, owns clients, sets its own selling prices.
  • Client: a bank, Sacco or other business that runs checks. A client belongs to DataCheck directly or to one reseller.

The super admin can make a direct client a reseller. It keeps its wallet, users and history, and can then add clients and set prices. (A client that belongs to a reseller cannot be converted, so a reseller never loses a client without a decision about who owns it.)

Suspending an organisation signs its users out and blocks sign-in, checks and incoming credit until it is restored. Clients of a suspended reseller cannot run checks either.

Roles and permissions

Each person belongs to one organisation and has one role. What they can do is the role's permissions, limited by what their kind of organisation can do. The table lives in lib/permissions.ts and is enforced on the server for every API route; the dashboard hides what a person cannot do.

Permission Owner Admin Operator Finance Viewer
Run checks (clients, resellers) yes yes yes
See check history yes yes yes yes yes
Refund a check (DataCheck only) yes yes
See credit and statement yes yes yes yes yes
Transfer credit (DataCheck, resellers) yes yes yes
Add or remove credit by hand (DataCheck only) yes yes
Request a top-up (clients, resellers) yes yes yes
Approve or reject top-ups (DataCheck, resellers) yes yes yes
See clients (DataCheck, resellers) yes yes yes yes
Add, suspend, convert clients (DataCheck, resellers) yes yes
See prices yes yes yes yes yes
Set prices (DataCheck, resellers) yes yes
See users yes yes yes
Manage users yes yes
Pull reports yes yes yes yes
Read the audit log yes yes yes
Edit organisation details and security rules yes yes
Manage API keys and webhooks (clients, resellers) yes yes

Owner and Admin differ in one way: only an owner can add, change or remove another owner. Every organisation keeps at least one active owner. Nobody can change their own role or deactivate themselves.

Clients can never transfer credit. Only DataCheck (to anyone) and resellers (to their own clients) can.

What each organisation sees:

  • DataCheck staff: every organisation.
  • Reseller users: their own organisation and their own clients.
  • Client users: their own organisation only.

Money

All amounts are Kenya shillings, stored in cents.

Wallets and the ledger. Every organisation has one wallet. Its balance only changes by writing a ledger entry, inside a database transaction that locks the wallet row. The ledger is append-only: the database refuses to edit or delete an entry, refuses a balance below zero, and refuses a balance change that does not match the latest entry. Entry types: topup, adjustment, transfer_in, transfer_out, check_charge, margin_credit, refund.

Where credit comes from. DataCheck issues credit. When a payment reaches DataCheck, the super admin approves the top-up request (or sends a transfer, or adds an adjustment with a reason). The DataCheck wallet itself is not debited: DataCheck is the issuer, and its revenue is reported from the checks, not held in a wallet.

Reseller credit. A reseller buys credit from DataCheck at face value (KES 10,000 paid gives KES 10,000 of credit). It passes credit to its clients by a transfer, or by approving a client's top-up request, which moves the amount from the reseller's wallet to the client's.

What a check costs.

Who runs it Charged Reseller gets DataCheck keeps
Direct client Base price (or a custom price DataCheck set for that client) All of it
A reseller's client The reseller's price for that client, else its default selling price, else the base price Selling price minus base, as margin_credit The base price
A reseller, for itself Base price (or a custom price DataCheck set for it) All of it

Example with the sample prices: Pwani Data Partners sells the KYC serial check at KES 25 (KES 23 for Mombasa Teachers Sacco). When the Sacco runs one, the Sacco's wallet goes down KES 23 and Pwani's goes up KES 3. CI checks this on every push.

A reseller cannot set a selling price below the base price. If DataCheck later raises a base price above a reseller's price, the base price is charged and the margin is zero until the reseller updates its price.

Why this model holds. The reseller paid face value for the credit it gave its client, so on each check the client's KES 23 of credit is used up: KES 20 is DataCheck's service and KES 3 returns to the reseller as margin. The reseller's margin arrives as credit in its wallet. It can use it for its own checks or pass it to clients. Paying margin out in cash is not built; if that is wanted later, it is a payout entry plus a bank or M-Pesa transfer.

Refunds. DataCheck staff can refund a check with a reason: the client gets the price back and, for a reseller's client, the reseller's margin is taken back.

Top-ups. A client or reseller requests a top-up after paying ("KES 10,000, reference QK12AB34CD"). The request goes to whoever sells them credit: DataCheck for resellers and direct clients, the reseller for its own clients. The approver checks the payment and approves (credit lands) or rejects with a reason. A reference can only be used once per organisation. Requests are stored with method = 'manual'; M-Pesa confirmation can be added later as method = 'mpesa' that approves itself when Safaricom confirms the payment.

Sign-in

  1. Email or phone number, plus password.
  2. A 6-digit code, every time. It is sent by SMS (Africa's Talking) when you sign in with your phone, by email (SMTP) when you sign in with your email, and falls back to the other if one is not set up. The code lasts 5 minutes, allows 5 tries, and can be re-sent 3 times. Only a hash of the code is stored.

People added by an owner get a temporary password, shown once to the person who added them, and choose their own at first sign-in.

Test mode (TEST_MODE=1, for the test domain): for test accounts only, the code is also shown on the sign-in screen in a marked box. Never set TEST_MODE on the live domain.

  1. Two-step sign-in (optional, or required by the organisation). People who turn it on in Settings, Security also enter the 6-digit code from an authenticator app (Google Authenticator, Microsoft Authenticator, Authy). Turning it on shows 10 one-time recovery codes, once. A recovery code works in place of the app code, one time each. The app secret is stored encrypted; recovery codes only as hashes. An owner or admin can require it for the whole organisation: people without it can then only open Settings, Security until they set it up. If someone loses their phone and their codes, an owner (or DataCheck) can reset it from Users and roles.

Passwords. At least 10 characters, not on the built-in list of common passwords (checked with digits and symbols at the ends removed, so "Password2026!" fails), no runs like 123456 or qwerty, and not containing the person's name, email or organisation name. No outside service is called.

Lockout. After 5 wrong passwords the account locks for 1 minute, then 2, 4, 8 and so on, up to 60 minutes per further wrong try. The right password does not work while it is locked. An owner or DataCheck can unlock it from Users and roles or the Security review page. Locks and wrong passwords go to the audit log.

Sessions. Settings, Security lists every place you are signed in (device and browser, IP address, when it started, last activity). Sign out one, or all others. Each organisation sets an idle timeout (5 minutes to 12 hours, default 1 hour); a session idle for longer ends.

Sign-in alerts. The first time someone signs in from a device DataCheck has not seen for them, it is recorded in the audit log, shown in their notifications, and sent by email or SMS when those are set up. Their very first device is only recorded.

IP allowlist (optional). An owner or admin can list the office IP addresses or ranges (like 197.248.10.0/24) the organisation may use. Sign-in, every dashboard request and every API key call from anywhere else is refused and logged. You cannot save a list that leaves out your own current address. DataCheck staff can change or clear any organisation's list from the Security review page (the override). Behind nginx, set TRUST_PROXY=1 so the real client address is used; without it the X-Forwarded-For header is ignored, so it cannot be forged.

Other protections: scrypt password hashing; a signed, httpOnly, SameSite=Lax session cookie (Secure in production) that lasts 12 hours and is ended at once by signing out, a password change, a reset or deactivation; rate limits on sign-in, codes, the assistant and API keys; changes only accepted as same-site JSON requests; parameterised SQL everywhere; server-side checks on every input.

Ask DataCheck (assistant)

Two tools in the top bar of the dashboard.

Search (Ctrl+K). A command palette. It finds pages you can open, your clients, recent checks, top-ups and sections of this guide. It works without any AI model.

Ask (Ctrl+J). A panel that:

  • answers how-to questions from this guide;
  • answers questions about your own figures (balance, checks and spend in the last 7 days, top-ups waiting);
  • opens pages: "take me to transfers";
  • prepares actions: "send 5,000 to Coast Microfinance", "approve top-up QKTEST0001", "invite Jane Achieng as operator", "set kyc serial price for Mombasa Teachers Sacco to 24".

How it stays safe:

  • Nothing runs by itself. A prepared action is a card with the details and a Confirm button. Pressing Confirm calls the same API route as the normal page, so every permission and money check applies again. The audit log marks it "confirmed in Ask DataCheck".
  • Your permissions only. The assistant can only look up and prepare what your role allows. A client cannot even prepare a transfer.
  • No personal data to the model. Before any text is sent, email addresses, phone numbers, ID and serial numbers, KRA PINs and long digit runs are replaced with placeholders. Lookups return only organisation names, amounts and counts. Contact details for an invite are typed on the card, never sent to the model.
  • Plain commands need no model. Commands like the ones above are understood by the server directly. Questions go to the language model only when one is configured.

The model is any OpenAI-compatible chat API; Groq is the default. Without a key the panel shows "Assistant not configured", and Search, commands and guide answers still work. Each question is logged in the audit log (not its text).

API and webhooks

Owners and admins of clients and resellers make API keys on the API keys page. A key is shown once; DataCheck keeps only a fingerprint. Each key has scopes: run checks, read check history, read balance. The organisation's IP allowlist applies to keys.

curl https://<site>/api/v1/balance -H "Authorization: Bearer bbx_live_..."
curl https://<site>/api/v1/checks -H "Authorization: Bearer bbx_live_..." \
  -H "Content-Type: application/json" \
  -d '{"product":"kra_pin","inputs":{"pin":"A012345678Z"}}'

Checks over the API are priced and charged exactly like the dashboard. Up to 120 calls a minute per key.

Webhooks. Set an https address on the API keys page. DataCheck POSTs check.completed and topup.decided events as JSON, signed with the organisation's secret: X-DataCheck-Signature: sha256=<HMAC-SHA256 of the body>. One try, 5-second timeout. Local and private addresses are refused.

Bulk checks

Paste rows or upload a CSV for one check (the input template has the column names; a header row is optional). The page checks every row before anything runs, lists the rows with problems, and shows the cost. Up to 500 rows per job.

The job runs in the background, one row at a time. Each row is charged through the same rules as a single check, in its own transaction: the client pays its price per row and a reseller gets its margin per row. If credit runs out, or the organisation is suspended, the job stops and the rows not run are not charged. Today the queue runs inside the web server; a job cut short by a restart carries on the next time anyone opens the bulk page. The architecture guide covers moving it to separate workers.

Protected results viewer. Results are for the person who ran the job only, for 24 hours. There is no download or export. Copy, select, right-click and print are turned off, printing gives a blank page, and a watermark with the viewer's name, email, organisation, time and a view id is tiled over the results. Results blur when the window loses focus, the tab is hidden, or developer tools are opened beside the page. Results are masked; revealing one row's full result is a deliberate action. Every page view and every reveal is in the audit log.

No website can stop a screenshot or a phone camera. These controls make copying hard and make any leak traceable to a person and a moment.

Notifications and alerts

The bell in the top bar lists top-up decisions, credit received, low credit and security events (new device, lockout, two-step sign-in turned off, recovery code used). In Settings, Security an owner or admin sets a low-credit level; when a payment takes the wallet below it, owners, admins and finance staff get a notification and owners an email or SMS.