Skip to content

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

  1. Integrator registers user: POST /v1/users {user_id: "ext_123"} OR: POST /v1/users {} (platform generates ID)
  2. User enrolls palm at integrator's scanner
  3. 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