11. Compliance & Consent¶
Consent, data-subject rights (export, deletion, withdrawal), audit logging, and retention.
11.1 Consent Management¶
When enabled: consent_required: true
The platform provides consent recording, status tracking, and enforcement. When enabled, the platform blocks palm enrollment and device-initiated transactions (/v1/device/enroll, /v1/device/transactions, plus the /v1/enroll challenge) if the user has not granted consent — returning HTTP 403 with error code consent_required. (Under the small model (§8.13) the platform is off the enroll path, so the device enforces this gate before the SDK enrolls; the platform then records the result.) API responses also include consent_status (e.g., "none" or "granted") so callers can show appropriate UI before attempting these operations.
Consent Capture Points:
- Product app / dashboard: User grants consent during onboarding via POST /v1/consent (user-JWT). When they later visit a device, consent is already on record.
- At the device (pos/kiosk): The device shows a consent screen and records consent via POST /v1/device/consent (mTLS) before enrollment — no vertical backend in the path (§13).
- Integrator-managed: External integrators capture consent in their own systems and record it via POST /v1/consent before calling enrollment/transaction endpoints.
API Endpoints: See Section 14.1 for consent endpoints (record, check, withdraw). The consent_records schema is in §5.5.
11.2 Data Subject Rights¶
When enabled: data_subject_rights_enabled: true
GET /v1/users/{id}/data— Export all user data (profile, identities, KYC, consent records, palm metadata). Palm templates are NOT exported.DELETE /v1/users/{id}— Delete user. Anonymizes PII, removes palm template from vendor, revokes tokens.
Diagram 7.1 — User Data Export (Right to Access)
sequenceDiagram
autonumber
participant User
participant App as Mobile App
participant Vertical as Vertical Backend
participant Identity as Identity Platform
participant Palm as X-Telcom BioWave Pass
participant DB as PostgreSQL
participant Audit as Audit Log
Note over Identity, Audit: All audit logging is conditional<br/>on tenant audit_enabled setting
User->>App: Request my data
App->>Vertical: POST /user/data-export
Vertical->>Identity: GET /v1/users/{user_id}/data<br/>Authorization: Bearer <token>
Identity->>DB: Get tenant config
DB-->>Identity: {data_subject_rights_enabled: true}
Identity->>DB: Fetch all user data
DB-->>Identity: User profile, identities,<br/>KYC data, consent records
rect rgb(255, 245, 230)
Note over Identity, Palm: Active palm metadata
Identity->>Palm: POST /KZ/query_palm_id<br/>Headers: request_id: <uuid><br/>Content-Type: application/json<br/>Body: {user_id}
Palm-->>Identity: {code: 0,<br/>data: {user_id, query_type,<br/>id_data_list: [{id, type}, ...]}}
Note over Identity: Template data NOT exported<br/>(only metadata: palm_id + type)
end
opt Include historical (deleted) palm metadata
Note over Identity, Palm: Forensic export — requires<br/>a current palm scan (only<br/>available if user can re-scan)
Identity->>Palm: POST /KZ/deleted_records<br/>Headers: request_id: <uuid><br/>Content-Type: multipart/form-data<br/>Body:<br/>- features_rgb.bin (optional)<br/>- features_ir.bin (optional)<br/>- image_rgb.png (required)<br/>- image_ir.png (required)<br/>- metadata: {type: "left",<br/>is_encrypted: false}
Palm-->>Identity: {code: 0,<br/>data: {deleted_records: [{user_id, id,<br/>type, scores: [4 floats],<br/>add_date_time, delete_date_time}, ...]}}
end
Identity->>Audit: Log: data_export<br/>(user_id, requester: user)
Identity-->>Vertical: {<br/> user: {id, created_at, status},<br/> identities: [{type, value, verified}],<br/> profile: {name, dob, ...},<br/> kyc: {status, provider, verified_at},<br/> consent: [{type, granted_at, purposes}],<br/> palm: {enrolled: true, type: "left",<br/> enrolled_at,<br/> deleted_history?: [...]}<br/>}
Vertical-->>App: Formatted data export
App-->>User: Download / View data
Diagram 7.2 — User Deletion (Right to Erasure)
sequenceDiagram
autonumber
participant User
participant App as Mobile App
participant Vertical as Vertical Backend
participant Identity as Identity Platform
participant Palm as X-Telcom BioWave Pass
participant DB as PostgreSQL
participant Audit as Audit Log
Note over Identity, Audit: All audit logging is conditional<br/>on tenant audit_enabled setting
User->>App: Delete my account
App->>Vertical: DELETE /user/account
Vertical->>Identity: DELETE /v1/users/{user_id}<br/>Authorization: Bearer <token>
Identity->>DB: Get tenant config
DB-->>Identity: {data_subject_rights_enabled: true}
Identity->>DB: Get user
DB-->>Identity: User found
rect rgb(255, 230, 230)
Note over Identity, Palm: Step 1: Delete palm template(s)
Identity->>Palm: POST /KZ/delete<br/>Headers: request_id: <uuid><br/>Content-Type: application/json<br/>Body: {user_id}
alt Success
Palm->>Palm: Remove all user's<br/>templates from Milvus
Palm-->>Identity: {code: 0, msg: "Success"}
else No records to delete
Palm-->>Identity: {code: 30006, msg: "ID not found"}
Note over Identity: Treat as idempotent success<br/>(user wasn't enrolled)
end
end
rect rgb(255, 245, 230)
Note over Identity, DB: Step 2: Anonymize user data
Identity->>DB: Anonymize user record<br/>(hash PII, keep audit ref)
Identity->>DB: Mark status = "deleted"
Identity->>DB: Revoke all refresh tokens
end
rect rgb(230, 255, 230)
Note over Identity, Audit: Step 3: Audit & notify
Identity->>Audit: Log: user_deleted<br/>(user_id, method: user_request,<br/>data_deleted: [palm, profile, identities])
Identity->>Identity: Publish UserDeleted event
opt Webhook subscribed
Identity->>Vertical: Send webhook: user.deleted<br/>{user_id, data_deleted}
end
end
Identity-->>Vertical: {status: "deleted",<br/>deleted_at: "..."}
Vertical->>Vertical: Clean up vertical-specific data
Vertical-->>App: "Account deleted"
App-->>User: Confirmation
Diagram 7.3 — Consent Withdrawal
sequenceDiagram
autonumber
participant User
participant App as Mobile App
participant Vertical as Vertical Backend
participant Identity as Identity Platform
participant Palm as X-Telcom BioWave Pass
participant DB as PostgreSQL
participant Audit as Audit Log
Note over Identity, Audit: All audit logging is conditional<br/>on tenant audit_enabled setting
User->>App: Withdraw consent
App->>Vertical: POST /consent/withdraw
Vertical->>Identity: POST /v1/consent/withdraw<br/>Authorization: Bearer <token><br/>{user_id, reason: "user_requested"}
Identity->>DB: Get active consent
DB-->>Identity: Consent found
Identity->>DB: Update consent<br/>(status: withdrawn, withdrawn_at)
Identity->>Audit: Log: consent_withdrawn<br/>(user_id, consent_id, reason)
rect rgb(255, 245, 230)
Note over Identity, Palm: Withdrawal triggers data cleanup
Identity->>Palm: POST /KZ/delete<br/>Headers: request_id: <uuid><br/>Content-Type: application/json<br/>Body: {user_id}
alt Success or no records
Palm-->>Identity: {code: 0} or {code: 30006}
end
Identity->>DB: Update user<br/>(palm_enrolled: false)
Identity->>DB: Revoke device certificates
end
Identity->>Identity: Publish ConsentWithdrawn event
opt Webhook subscribed
Identity->>Vertical: Send webhook: consent.withdrawn<br/>{user_id, consent_id,<br/>actions_taken: ["palm_deleted",<br/>"devices_revoked"]}
end
Identity-->>Vertical: {consent_id,<br/>status: "withdrawn",<br/>actions_taken: [...]}
Vertical-->>App: "Consent withdrawn"
App-->>User: "Your consent has been<br/>withdrawn and biometric<br/>data deleted"
11.3 Audit Logging¶
When enabled: audit_enabled: true (default)
Logs all business events with full context: IP address, user agent, actor, result, and event-specific metadata. When disabled, no audit events are recorded — tenants that don't need audit logging can turn it off.
- Common fields on every audit event (
event_id,event_type,timestamp,tenant_id,actor,ip_address,user_agent,result,metadata): defined with theaudit_logschema in §5.5. - Full event-type catalog: §16 (Event Reference), which lists every audit event alongside its webhook counterpart (where one exists).
11.4 Data Retention¶
| Data Type | Retention |
|---|---|
| Audit logs | 10 years (SAMA requirement) |
| Consent records | 5 years |
| KYC data | Until deleted |
| Palm templates | Until deleted |
| User profiles | Until deleted |
| Refresh tokens | 30 days |