@rdhiq/rdh-fp
v1.3.7
Published
React SDK for fingerprint capture, validation and submission via Neurotechnology Device Server
Readme
@rdhiq/rdh-fp
React SDK for fingerprint capture, validation, enrollment, verification, identification, transaction browsing, and fingerprint image previewing with Neurotechnology Device Server and RD.FingerPrint.API middleware.
Installation
npm install @rdhiq/rdh-fpyarn add @rdhiq/rdh-fpbun add @rdhiq/rdh-fpPeer dependencies:
npm install react react-domBasic Setup
Import the package CSS once, then mount FingerprintProvider around any SDK components.
import "@rdhiq/rdh-fp/style.css";
import {
FingerprintProvider,
FingerprintModal,
FingerprintButtonEnroll,
FingerprintButtonVerify,
FingerprintButtonIdentify,
FingerprintButtonUpsert,
} from "@rdhiq/rdh-fp";
export default function App() {
return (
<FingerprintProvider
initialConfig={{
deviceServer: {
baseUrl: "http://127.0.0.1",
port: 8041,
},
middleware: {
baseUrl: "http://10.254.210.55:5000",
userId: "EMP-1001",
callerSystem: "notary-web",
},
}}
onSuccess={(result) => console.log("Capture success", result)}
onError={(message, result) => console.error("Capture error", message, result)}
>
<FingerprintButtonEnroll params={{ personId: "P-001", nationalId: "11000345678901001" }}>
Enroll
</FingerprintButtonEnroll>
<FingerprintButtonVerify params={{ personId: "P-001" }}>
Verify
</FingerprintButtonVerify>
<FingerprintButtonUpsert params={{ personId: "P-001", nationalId: "11000345678901001" }}>
Upsert
</FingerprintButtonUpsert>
<FingerprintButtonIdentify params={{ topK: 5 }}>
Identify
</FingerprintButtonIdentify>
<FingerprintModal />
</FingerprintProvider>
);
}FingerprintModal should be mounted once inside the provider. The buttons and hook open that modal in the correct operation mode.
Provider Configuration
FingerprintProvider merges defaults, saved browser settings, and initialConfig. Use the designSystem prop when the host app should control package colors and spacing from code.
<FingerprintProvider
designSystem={{
preset: "biometric",
density: "comfortable",
radius: 10,
colors: {
primary: "#14b8a6",
secondary: "#4f46e5",
success: "#16a34a",
warning: "#d97706",
danger: "#e11d48",
surface: "#0b1320",
surfaceAlt: "#121d2e",
text: "#eef7f5",
textMuted: "#9eb3c2",
},
}}
initialConfig={{
deviceServer: {
baseUrl: "http://127.0.0.1",
port: 8041,
deviceId: null,
timeoutMs: 15000,
},
middleware: {
baseUrl: "https://your-middleware.example.com",
userId: "EMP-1001",
callerSystem: "notary-web",
accessToken: undefined,
apiKey: undefined,
},
}}
>
{children}
</FingerprintProvider>Design System
designSystem accepts preset, density, radius, and partial colors. Presets are biometric, civic, ocean, and slate; use custom when you want to provide your own palette.
Device Server
| Field | Type | Description |
| --- | --- | --- |
| baseUrl | string | Device Server host, usually http://127.0.0.1 |
| port | number | Device Server port |
| deviceId | string \| null | Selected scanner device |
| timeoutMs | number | Request timeout in milliseconds |
| captureParams | Record<string, unknown> | Optional Device Server capture configuration |
Middleware
| Field | Type | Description |
| --- | --- | --- |
| baseUrl | string | RD.FingerPrint.API base URL |
| userId | string | Operator id, sent as x-user-id |
| callerSystem | string | Client application id, sent as x-caller-system |
| accessToken | string \| null | Optional bearer token |
| apiKey | string \| null | Optional API key, sent as x-api-key when no bearer token is used |
Operation Params
All capture buttons and hook methods accept CaptureOperationParams without the internal mode field.
const operationParams = {
personId: "A4412188-A29C-48BE-8136-536D6B235009",
transactionId: "SALE-2026-1009",
nationalId: "11000345678901009",
userId: "EMP-1001",
transactionName: "Fingerprint demo transaction",
debug: true,
};Common fields:
| Field | Type | Description |
| --- | --- | --- |
| requestId | string | Optional host request id. If omitted, the SDK generates one. |
| personId | string | Person identifier for enroll, verify, update, and upsert. |
| transactionId | string | Business transaction id. |
| nationalId | string | National identity document id. |
| fullName | string | Person full name. |
| citizenName | string | Person display name shown in the modal. |
| employeeName | string | Operator display name shown in the modal. |
| transactionName | string | Transaction display name shown in the modal and sent to middleware. |
| transactionType | string | Optional transaction type/category. |
| userId | string | User/operator id for this operation. |
| projectId | string | Optional project id. |
| fingerIndex | number | ANSI/NIST finger position code. |
| fingerPositions | FingerPosition[] | One or more selected finger positions. |
| fingers | FingerConfig[] | Custom finger selector labels, ids, and selectable flags. |
| threshold | number | Verification/identification threshold. |
| topK | number | Number of identify candidates to return. |
| allowReducedAcceptance | boolean | Allow reduced mode when validation rules permit it. |
| overrideToken | string | Backend override token for reduced acceptance. |
| debug | boolean | Show the modal debug panel. |
Capture Buttons
<FingerprintButtonEnroll params={operationParams}>
Enroll
</FingerprintButtonEnroll>
<FingerprintButtonVerify params={operationParams}>
Verify
</FingerprintButtonVerify>
<FingerprintButtonUpsert params={operationParams}>
Upsert
</FingerprintButtonUpsert>
<FingerprintButtonIdentify params={{ ...operationParams, topK: 5 }}>
Identify
</FingerprintButtonIdentify>Each button also accepts normal button props plus per-call callbacks:
<FingerprintButtonUpsert
params={operationParams}
onSuccess={(result) => console.log("Upsert success", result)}
onError={(message, result) => console.error("Upsert failed", message, result)}
>
Upsert
</FingerprintButtonUpsert>Programmatic Usage
Use useFingerprint() inside FingerprintProvider.
import { useFingerprint } from "@rdhiq/rdh-fp";
function CaptureActions() {
const {
openEnroll,
openVerify,
openUpsert,
openIdentify,
isModalOpen,
lastResult,
} = useFingerprint();
return (
<>
<button disabled={isModalOpen} onClick={() => openEnroll({ personId: "P-001" })}>
Enroll
</button>
<button disabled={isModalOpen} onClick={() => openVerify({ personId: "P-001" })}>
Verify
</button>
<button
disabled={isModalOpen}
onClick={() =>
openUpsert(
{ personId: "P-001", nationalId: "11000345678901001" },
{ onSuccess: (result) => console.log(result) },
)
}
>
Upsert
</button>
<button disabled={isModalOpen} onClick={() => openIdentify({ topK: 5 })}>
Identify
</button>
<pre>{JSON.stringify(lastResult, null, 2)}</pre>
</>
);
}Returned values:
| Value | Description |
| --- | --- |
| openEnroll | Opens enrollment capture. |
| openVerify | Opens verification capture. |
| openUpsert | Opens enroll-or-update capture through the v2 decision flow. |
| openUpdate | Opens explicit update capture. |
| openIdentify | Opens 1:N identification capture. |
| openPreEnrollCheck | Opens pre-enrollment duplicate check. |
| config | Current SDK configuration. |
| updateConfig | Replace and persist SDK configuration. |
| theme | Current theme. |
| setTheme | Set light or dark. |
| isModalOpen | Whether a modal capture session is active. |
| modalState | Current modal state. |
| lastResult | Latest CaptureResult. |
Upsert Decision Flow
FingerprintButtonUpsert and openUpsert() use:
POST /api/v2/fingerprints/upsert-decisionThe SDK then follows the middleware decision:
| Decision | SDK behavior |
| --- | --- |
| Enroll | Submits to the v1 enroll endpoint. |
| Upsert | Submits to the v1 upsert endpoint. |
| Update | Submits to the v1 update endpoint. |
| LinkExistingSubject | Links to the existing ABIS subject and updates biometric data. |
| ManualReview | Opens the manual review modal so the operator can select a candidate. |
| Reject | Fails the operation with the middleware message. |
Fresh request ids are generated for mutating calls after a decision when needed, so the decision request id is not reused in a way that can trigger duplicate request errors.
Finger Selection
Use fingers to customize labels, ids, and selectable fingers.
import { FINGER_POSITIONS, type FingerConfig } from "@rdhiq/rdh-fp";
const fingers: FingerConfig[] = [
{
position: FINGER_POSITIONS.RIGHT_THUMB,
label: "Right thumb",
id: "f-rt",
selectable: true,
},
{
position: FINGER_POSITIONS.RIGHT_INDEX_FINGER,
label: "Right index",
id: "f-ri",
selectable: false,
},
];
<FingerprintButtonEnroll params={{ personId: "P-001", fingers }}>
Enroll
</FingerprintButtonEnroll>;Fingers omitted from the custom list fall back to SDK defaults.
Fingerprint Image
FingerprintImage fetches a stored transaction fingerprint image by personId and transactionId.
import { FingerprintImage } from "@rdhiq/rdh-fp";
<FingerprintImage
personId="A4412188-A29C-48BE-8136-536D6B235009"
transactionId="SALE-2026-1009"
width={180}
height={180}
alt="Transaction fingerprint"
/>;The component calls:
GET /api/v1/persons/{personId}/transactions/{businessTransactionId}/fingerprintstype is optional. The SDK does not send ?type=ORIGINAL by default.
<FingerprintImage
personId="P-001"
transactionId="SALE-2026-1009"
type="ENHANCED"
/>Transactions Page
TransactionsPage provides a transaction browser and a detail drawer.
import { TransactionsPage } from "@rdhiq/rdh-fp";
function TransactionsRoute() {
return <TransactionsPage />;
}The list uses:
GET /api/v1/workflow/transactionsSupported filters:
| Filter | Query parameter |
| --- | --- |
| Transaction ID | transactionId |
| Person ID | personId |
| Client Application ID | clientApplicationId |
| Project ID | projectId |
Opening a row fetches full details by id:
GET /api/v1/workflow/transactions/{businessTransactionId}The detail drawer shows:
- transaction metadata
- person and identity document fields
- ABIS status fields
- request cards
- request status history timeline
- candidate count and top score where available
- ABIS transaction and encounter ids
- error code/message where available
Settings Page
SettingsPage lets a host app manage SDK settings from the UI.
import { SettingsPage } from "@rdhiq/rdh-fp";
function SettingsRoute() {
return <SettingsPage />;
}It supports:
- light/dark theme
- device discovery and selection
- middleware validation profile loading
- project policy loading by project id
- mandatory and optional finger policy display
Capture Result
interface CaptureResult {
success: boolean;
operationMode:
| "enrollment"
| "upsert"
| "update"
| "verification"
| "identification"
| "pre_enroll_check";
captureMode: "standard" | "reduced";
sensorData: string | null;
captureId: string | null;
metadata: Record<string, string | number | boolean | null>;
deviceId: string;
dsVersion: string | null;
rulesVersion: string | null;
sessionId: string | null;
correlationId: string;
backendResponse?: BackendSubmitResponse;
error?: string;
}Common backend response fields:
| Field | Description |
| --- | --- |
| fingerprintRecordId | Enrolled or updated fingerprint record id. |
| qualityScore | Quality score returned by middleware. |
| matched | Verification match result. |
| score | Verification or candidate score. |
| candidatePersonId | Matched person id. |
| candidates | Identification candidates. |
| requestId | Middleware request id. |
| abisTransactionRequestId | ABIS transaction request id. |
| abisEncounterId | ABIS encounter id. |
Low-Level Clients
The package exports clients for advanced integrations.
import { MiddlewareClient, DeviceServerClient } from "@rdhiq/rdh-fp";
const middleware = new MiddlewareClient(
"https://your-middleware.example.com",
"EMP-1001",
"notary-web",
);
const transactions = await middleware.getTransactions({
transactionId: "SALE-2026-1009",
});
const detail = await middleware.getTransactionById(
"8b511243-f4ff-47fd-b85a-473fd16057d3",
);
const images = await middleware.getPersonTransactionFingerprints(
"A4412188-A29C-48BE-8136-536D6B235009",
"SALE-2026-1009",
);
const deviceServer = new DeviceServerClient("http://127.0.0.1", 8041, 15000);
const devices = await deviceServer.getDevices();Configuration Utilities
import {
DEFAULT_CONFIG,
STORAGE_KEY,
clearConfig,
loadConfig,
saveConfig,
} from "@rdhiq/rdh-fp";
const config = loadConfig();
saveConfig({
...config,
middleware: {
...config.middleware,
baseUrl: "https://your-middleware.example.com",
},
});
clearConfig();
console.log(STORAGE_KEY, DEFAULT_CONFIG);Runtime Requirements
- React 18 or newer.
- A reachable Neurotechnology Device Server for real biometric capture.
- A reachable RD.FingerPrint.API middleware.
- Browser access to the Device Server and middleware URLs.
- CORS must allow the host app origin.
x-user-idis required for middleware write operations.x-caller-systemshould identify the host application.
Troubleshooting
| Problem | Check |
| --- | --- |
| No device selected | Open SettingsPage, load devices, and select a device. |
| Device Server offline | Confirm host and port, for example http://127.0.0.1:8041. |
| Middleware offline | Confirm middleware.baseUrl and network access. |
| CORS error | Enable CORS for the host app origin or use a dev proxy. |
| Duplicate request id | Omit requestId unless the host must control it. The SDK generates safe ids when needed. |
| Fingerprint image URL has unsupported query | Do not pass type; the SDK no longer sends ?type=ORIGINAL by default. |
| Public HTTPS app cannot call local HTTP services | Browsers may block mixed content. Use HTTPS-capable middleware/device access or run the app locally. |
