13. User Journeys¶
End-to-end journeys that compose the capabilities — initiation patterns, enrollment paths, and transaction flows.
13.1 Initiation Patterns¶
| Pattern | Who Initiates | Path | Use Cases |
|---|---|---|---|
| Integrator-initiated | Integrator backend | Backend creates a challenge → personal scanner polls (§9.2) | E-signature |
| Device-initiated | User scans at the device | Device → Identity (mTLS) → 1:N identify → broker authorize → in-band decision (§10) |
POS payment, access entry |
13.2 Enrollment Paths¶
Account creation and palm enrollment are separate lifecycles (§5.2). The account is keyed by mobile number and can be created in a product app/dashboard or at a device in signup mode; the palm is always enrolled at a physical device (pos/kiosk). All device steps are device→Identity over mTLS — no vertical backend in the path.
Path A: App-first (account in app, enroll later at a device)
1. User signs up in a product app/dashboard (OTP/email/social → user-JWT)
2. User completes KYC in the app (if the product requires it)
3. User accepts consent in the app → recorded via POST /v1/consent (user-JWT)
4. App shows palm_enrolled: false → prompts "enroll at a POS/kiosk"
5. At a device → POST /v1/device/signup + /signup/verify (mobile OTP) locates the account → POST /v1/device/enroll captures the palm (consent already on record → proceeds directly)
Path B: App signup, consent + enroll at the device
1. User signs up in the app (steps 1–2 as above); consent not yet granted
2. At the device, after OTP the response shows consent_status: none
3. Device shows a consent screen → POST /v1/device/consent (mTLS) → POST /v1/device/enroll
Path C: POS signup mode (new user, everything at the device)
1. User at a POS/kiosk → POST /v1/device/signup with mobile → OTP via SMS
2. POST /v1/device/signup/verify → account created (is_new_user: true, palm_enrolled: false)
3. If the product requires KYC and the user is unverified → direct them to complete KYC first
4. consent_status: none → device shows consent screen → POST /v1/device/consent
5. POST /v1/device/enroll captures the palm → palm_enrolled: true
All device-side palm enrollment converges at POST /v1/device/enroll (mTLS). The platform does not enforce KYC — it surfaces KYC status and the product decides whether to gate on it. When consent_required: true, the platform enforces consent — enrollment and transaction endpoints reject requests without granted consent (HTTP 403, consent_required). Once enrolled, the palm is recognized across all Link Holdings products (§4.6).
Diagram 6.1 — Complete User Onboarding (Signup → KYC → Consent → Palm)
sequenceDiagram
autonumber
participant User
participant App as Wallet Mobile App
participant Wallet as Wallet Backend
participant Identity as Identity Platform
participant Nafath as Nafath
participant NafathApp as Nafath App
participant Kiosk as POS / Kiosk
participant Palm as X-Telcom BioWave Pass
participant Audit as Audit Log
Note over Identity, Audit: All audit logging is conditional<br/>on tenant audit_enabled setting
rect rgb(230, 245, 255)
Note over User, Audit: Phase 1: Mobile Signup
User->>App: Download app, enter mobile
App->>Identity: Send OTP
Identity->>Audit: Log: otp_sent
Identity-->>User: SMS with OTP
User->>App: Enter OTP
App->>Identity: Verify OTP
Identity->>Identity: Create user
Identity->>Audit: Log: user_created
Identity->>Audit: Log: token_issued
Identity-->>App: {access_token, user_id}
App-->>User: "Welcome!"
end
rect rgb(255, 245, 230)
Note over User, Audit: Phase 2: KYC Verification
User->>App: Tap "Verify Identity"
App->>Wallet: Start KYC
Wallet->>Identity: Initiate KYC
Identity->>Audit: Log: kyc_initiated
Identity->>Nafath: Request verification
Nafath-->>Identity: {transId, random: "47"}
Identity-->>App: Display "47"
User->>NafathApp: Open, select "47"
NafathApp->>Nafath: Confirm
Nafath->>Identity: Callback (verified)
Identity->>Audit: Log: kyc_verified
Identity-->>App: "Identity verified!"
end
opt Consent from mobile (optional)
Note over User, Audit: Phase 2B: Mobile Consent
User->>App: Tap "Grant Consent"
App->>Wallet: Grant consent
Wallet->>Identity: POST /v1/consent<br/>{user_id, consent_type: "biometric_enrollment"}
Identity->>Audit: Log: consent_granted
Identity-->>App: {consent_id, status: "granted"}
App-->>User: "Consent recorded"
end
rect rgb(230, 255, 230)
Note over User, Audit: Phase 3: Palm Enrollment at POS (device-direct, mTLS)
User->>Kiosk: Go to kiosk, enter mobile
Kiosk->>Identity: POST /v1/device/signup (mTLS)<br/>{mobile} → Send OTP
User->>Kiosk: Enter OTP
Kiosk->>Identity: POST /v1/device/signup/verify (mTLS)
Identity-->>Kiosk: {user_id, palm_enrolled: false,<br/>kyc_status ✓, consent_status}
alt Consent already granted (from app)
Note over Kiosk: Skip consent screen
else Consent not on record
Kiosk-->>User: "Consent required for<br/>biometric enrollment"
User->>Kiosk: Accept consent
Kiosk->>Identity: POST /v1/device/consent (mTLS)
Identity->>Audit: Log: consent_granted
end
Kiosk-->>User: "Place palm"
User->>Kiosk: Scan palm
Kiosk->>Identity: POST /v1/device/enroll (mTLS)<br/>{user_id, scan}
Note right of Identity: Optional: /KZ/query duplicate check<br/>(see Section 4.1)
Identity->>Palm: POST /KZ/add<br/>(request_id header, tenant-prefixed user_id)
Palm-->>Identity: {code: 0, data: {id: 100001}}
Identity->>Audit: Log: palm_enrolled
Identity-->>Kiosk: {palm_enrolled: true}
end
rect rgb(245, 230, 255)
Note over User, Audit: Phase 4: First Transaction (device-initiated broker)
User->>User: Go to merchant, place palm on POS
Note right of User: POS → Identity POST /v1/device/transactions (mTLS)<br/>→ /KZ/query 1:N (4 scores/thresholds)<br/>→ broker authorize → Wallet decides (§10)
Identity->>Audit: Log: device_transaction (allow)
User->>User: Payment approved!
end
13.3 Transaction Flows¶
POS Payment / Access Entry (device-initiated, 1:N → broker)
1. User scans palm at the pos/gate device
2. Device → Identity: POST /v1/device/transactions (mTLS) with {scan, context, idempotency_key}
3. Identity runs 1:N identify, then calls the bound product's authorize endpoint (§10)
4. Product returns allow/deny (+ display message) → Identity relays it to the device in-band
5. Device acts on the decision (open gate / show "Approved"). No vertical backend on the path; the device never sees a user_id
E-Signature (1:1 Verification via Challenge) 1. Integrator creates challenge: POST /v1/verify {user_id, device_id} 2. Personal scanner polls for the challenge → user scans palm 3. Identity verifies against the enrolled template → returns match result + metadata 4. Integrator stores verification metadata as proof of signature
13.4 Integrator Flow¶
- Integrator registers user: POST /v1/users {user_id: "ext_123"} OR: POST /v1/users {} (platform generates ID)
- User enrolls palm at integrator's scanner
- For future transactions: challenge-based verification (personal scanner) or device-initiated transactions (pos/gate — §10)
13.5 User Lifecycle¶
Applies to all tenants. Steps are included based on tenant configuration.
1. User Registration: POST /v1/users with optional user_id (maps if provided, generates if not) — or self-signup via auth endpoints
2. Auth Setup: Configure auth methods (OTP, password, social) — if auth enabled
3. Account Linking: Additional auth methods automatically linked to same user
4. KYC: Verify identity via configured provider — if KYC enabled
5. Verification Enforcement: If `require_email_verified` or `require_mobile_verified` is enabled, users must verify the respective contact method before proceeding to palm enrollment (HTTP 403 if not verified)
6. Palm Enrollment: at a physical device (POS/kiosk) — user verifies (mobile OTP + consent), then scans palm. An account created in an app/dashboard shows `palm_enrolled: false` until the user enrolls at a device; palm capture never happens in an app
7. Active Use: User can authenticate and transact with palm
8. Deletion: Integrator backend or admin requests deletion → data removed per DSR policy