14. API Specification¶
14.1 Integrator API¶
| Endpoint | Method | Auth | Purpose |
|---|---|---|---|
/v1/auth/token |
POST | Various | Get tokens |
/v1/auth/register |
POST | None | Email signup |
/v1/auth/otp/send |
POST | None | Send OTP |
/v1/auth/password/reset |
POST | None | Reset password |
/v1/auth/password/change |
POST | User JWT | Change password |
/v1/auth/revoke |
POST | User JWT | Revoke token |
/.well-known/jwks.json |
GET | Public | Public keys |
/v1/users |
POST | client_credentials | Register user (generates or maps user_id) |
/v1/users/{id} |
GET | client_credentials | Get user |
/v1/users/{id} |
PATCH | client_credentials | Update user |
/v1/users/{id} |
DELETE | client_credentials | Delete user |
/v1/users/{id}/data |
GET | client_credentials | Export data |
/v1/users/{id}/identities |
GET | client_credentials | List identities |
/v1/users/{id}/identities |
POST | client_credentials | Link identity |
/v1/users/{id}/identities/{type} |
DELETE | client_credentials | Unlink |
/v1/kyc/initiate |
POST | client_credentials | Start KYC — [POST-MVP], see §7 |
/v1/kyc/status/{user_id} |
GET | client_credentials | Get KYC status — [POST-MVP], see §7 |
/v1/kyc/callback/{provider} |
POST | Provider signature | KYC provider webhook — [POST-MVP], see §7 |
/v1/enroll |
POST | client_credentials | Create enroll challenge (personal scanner). pos/kiosk use /v1/device/enroll instead |
/v1/verify |
POST | client_credentials | Create verify challenge (1:1, includes device_id) — e-signature |
/v1/challenges/{id} |
GET | client_credentials | Check challenge status |
/v1/challenges/pending |
GET | mTLS (device cert) | Poll for pending challenges (personal scanner) |
/v1/challenges/{id}/complete |
POST | mTLS (device cert) | Submit palm for a challenge (personal scanner) |
/v1/device/transactions |
POST | mTLS (device cert) | Device-initiated palm transaction (pos/gate): scan → 1:N identify → broker authorize → in-band {decision, display_message, product_reference}. Body {scan, context, idempotency_key}. See §10 |
/v1/device/signup |
POST | mTLS (device cert) | POS signup mode — start: find/create Identity user by mobile, send OTP. Body {mobile} → {challenge_id} |
/v1/device/signup/verify |
POST | mTLS (device cert) | POS signup — verify OTP, create user if new. Body {challenge_id, code} → {user_id, is_new_user, palm_enrolled} |
/v1/device/consent |
POST | mTLS (device cert) | Record consent at the device for the current user (replaces vertical-backend capture). Body {user_id, consent_type, version} |
/v1/device/enroll |
POST | mTLS (device cert) | Device palm enrollment: bind a captured palm to the user. Body {user_id, scan} → {palm_enrolled: true}. Consent/KYC gates per §11/§13 |
/v1/devices |
GET | client_credentials | List devices |
/v1/devices |
POST | client_credentials | Register device (tenant-scoped). Body includes device_class; for pos/gate/kiosk, bound_product + bound_action (§9.3) |
/v1/devices/{id} |
PUT | client_credentials | Update device binding (bound_product, bound_action) + metadata |
/v1/devices/{id} |
DELETE | client_credentials | Revoke |
/v1/devices/pair |
POST | Pairing Code | Pair scanner + issue certificate. Body: {pairing_code, csr, device_info: {model, firmware, serial, hardware_id}}. Returns {device_id, certificate, ca_chain, expires_at, status}. See §9.2.1. |
/v1/devices/renew |
POST | mTLS (device cert) | Renew certificate. Body: {csr} (new keypair, signed by new private key). Returns {certificate, ca_chain, expires_at}. Old cert fingerprint added to denylist on success. |
/v1/clients |
POST | Console session | Create OAuth client (returns secret once) |
/v1/clients |
GET | Console session | List clients for tenant |
/v1/clients/{id} |
DELETE | Console session | Revoke client |
/v1/clients/{id}/regenerate |
POST | Console session | Regenerate secret (returns new secret once, old one invalidated) |
/v1/webhooks |
POST | Console session | Create webhook endpoint (returns signing secret once) |
/v1/webhooks |
GET | Console session | List webhook endpoints for tenant |
/v1/webhooks/{id} |
PATCH | Console session | Update URL or event subscriptions |
/v1/webhooks/{id} |
DELETE | Console session | Delete webhook endpoint |
/v1/webhooks/{id}/regenerate |
POST | Console session | Regenerate signing secret |
/v1/linked-services |
POST | Console session (Tenant Admin) | Register a product backend for device-initiated routing (product_key, base_url, authorize_path, health_path, timeout_ms, fail_mode) — see §10 |
/v1/linked-services |
GET | Console session | List linked services for the tenant, incl. each service's health_status + last_health_check_at (§10.7) |
/v1/linked-services/{id} |
PATCH | Console session (Tenant Admin) | Update a linked service (URL, health_path, timeout, fail_mode) |
/v1/linked-services/{id} |
DELETE | Console session (Tenant Admin) | Remove a linked service |
/v1/consent |
POST | client_credentials | Record |
/v1/consent/{user_id} |
GET | client_credentials | Check |
/v1/consent/withdraw |
POST | client_credentials | Withdraw |
/v1/users/{user_id}/palm-restriction |
PUT | Console session (Tenant Admin/Operator) | Set per-user palm type restriction (left/right/all/disable) — see §8.11 |
/v1/users/{user_id}/palm-restriction |
GET | Console session | Get current restriction for user |
The device-facing palm endpoints above —
/v1/device/transactions,/v1/device/enroll, and the challenge-based/v1/verify//v1/enroll//v1/challenges/{id}/complete— carry device-reported results under the small model and scans/features under the large model; request payload and platform handling differ by the active palm model (§8.13).
14.2 Console API (MVP)¶
All Console API endpoints require a valid console session. The tenant_id is extracted from the session — callers cannot specify a different tenant. Platform Admin endpoints are additionally restricted by role.
Pagination: All list endpoints support ?page=1&page_size=50&sort=created_at&order=desc plus endpoint-specific filters.
Tenant Configuration
| Endpoint | Method | Auth | Purpose |
|---|---|---|---|
/v1/tenant/config |
GET | Console session | Get current tenant configuration (all §4.5 settings) |
/v1/tenant/config |
PATCH | Console session (Tenant Admin) | Partial update of tenant config — any subset of §4.5 settings (auth_methods, kyc_required, kyc_provider, palm_provider, consent_required, audit_enabled, etc.) |
Platform Administration (Platform Admin only)
| Endpoint | Method | Auth | Purpose |
|---|---|---|---|
/v1/admin/tenants |
GET | Console session (Platform Admin) | List all tenants with status and identity count |
/v1/admin/tenants |
POST | Console session (Platform Admin) | Create tenant (returns tenant_id, first Tenant Admin credentials) |
/v1/admin/tenants/{id} |
GET | Console session (Platform Admin) | Get tenant details + config |
/v1/admin/tenants/{id} |
PATCH | Console session (Platform Admin) | Update tenant name, region |
/v1/admin/tenants/{id}/suspend |
POST | Console session (Platform Admin) | Suspend tenant |
/v1/admin/tenants/{id}/reactivate |
POST | Console session (Platform Admin) | Reactivate suspended tenant |
/v1/admin/tenants/{id}/deactivate |
POST | Console session (Platform Admin) | Initiate deletion (30-day grace period) |
/v1/admin/palm/thresholds |
GET | Console session (Platform Admin) | Get current vendor thresholds (4-element array) — see §8.12.2 |
/v1/admin/palm/thresholds |
PUT | Console session (Platform Admin) | Update vendor thresholds — triggers palm_thresholds_updated audit event |
/v1/admin/palm/health |
GET | Console session (Platform Admin) | Last vendor health check status — see §8.12.1 |
/v1/admin/palm/model |
GET | Console session (Platform Admin) | Get the deployment's active palm model (small/large) + migration_status — see §8.13 |
/v1/admin/palm/verification-server |
GET/PUT | Console session (Platform Admin) | Get/set the deployment's verification-server connection endpoint (URL); required to run the migration script and for large-model operation — see §8.14 |
/v1/admin/palm/migrate |
POST | Console session (Platform Admin) | Trigger small→large migration: run the vendor script against the configured verification server, monitor, switch model. Triggers palm_model_migration_started — see §8.14 |
Platform SSL / Certificate Management (Platform Admin only — see §9.2.2)
| Endpoint | Method | Auth | Purpose |
|---|---|---|---|
/v1/admin/ssl/server-cert |
GET | Console session (Platform Admin) | Get current server TLS cert metadata (issuer, subject, expiry, days remaining, fingerprint) |
/v1/admin/ssl/server-cert |
PUT | Console session (Platform Admin) | Upload new server cert + key (multipart). Validates pair, hot-reloads uvicorn. Audit: server_cert_uploaded |
/v1/admin/ssl/server-cert |
DELETE | Console session (Platform Admin) | Remove the server TLS cert; backend reverts to plain HTTP on next process restart (rare — only for re-running first-run setup). Audit: server_cert_deleted |
/v1/admin/ssl/ca-cert |
GET | Console session (Platform Admin) | Get platform CA metadata + public cert PEM |
/v1/admin/ssl/ca-cert |
PUT | Console session (Platform Admin) | Upload existing CA cert + key (for orgs migrating from a CA they already run). Audit: platform_ca_generated |
/v1/admin/ssl/ca-cert/generate |
POST | Console session (Platform Admin) | Generate a new ECDSA P-256 CA keypair (self-signed, 10-year). Audit: platform_ca_generated |
/v1/admin/ssl/ca-cert/regenerate |
POST | Console session (Platform Admin) | DESTRUCTIVE — same as generate, but invalidates all existing device certs. Requires explicit confirm step. Audit: platform_ca_regenerated (high-severity) |
/v1/admin/ssl/device-policy |
GET | Console session (Platform Admin) | Get current device cert validity + renewal-window policy |
/v1/admin/ssl/device-policy |
PUT | Console session (Platform Admin) | Update device cert policy. Audit: device_policy_changed |
/v1/admin/ssl/status |
GET | Console session (Platform Admin) | Reports {server_cert_configured, platform_ca_configured, setup_complete}. Used by the SSL Settings page to decide whether to render the inline first-run setup wizard. |
User Management (Console)
| Endpoint | Method | Auth | Purpose |
|---|---|---|---|
/v1/users |
GET | Console session | List/search users. Params: ?search=&status=&kyc_status=&palm_enrolled=&page=1&page_size=50 |
/v1/users/{id}/suspend |
POST | Console session (Tenant Admin) | Suspend user (triggers user_suspended audit event + user.suspended webhook) |
/v1/users/{id}/reactivate |
POST | Console session (Tenant Admin) | Reactivate user (triggers user_reactivated audit event + user.reactivated webhook) |
Audit Logs
| Endpoint | Method | Auth | Purpose |
|---|---|---|---|
/v1/audit-logs |
GET | Console session | Query audit logs. Params: ?event_type=&user_id=&date_from=&date_to=&page=1&page_size=50 |
Dashboard
| Endpoint | Method | Auth | Purpose |
|---|---|---|---|
/v1/tenant/stats |
GET | Console session | Dashboard KPIs: total identities, active enrollments, consent opt-in rate, auth activity, KYC pipeline breakdown, user status breakdown |
14.3 Console API (Post-MVP)¶
The following endpoints are planned but not in the initial release:
| Endpoint | Method | Purpose |
|---|---|---|
/v1/kyc/sessions |
GET | KYC session listing with filters (status, provider, date range) — see §7 |
/v1/tenant/sms-config |
PATCH | SMS provider configuration (provider, sender ID) |
/v1/audit-logs/archive-search |
POST | Long-term audit archive search (>12 months) |
/v1/consent/records |
GET | Consent record listing with filters (type, status, date range) |
14.4 Response Metadata¶
Device Transaction Response (POST /v1/device/transactions):
The device receives only a decision and a display string — never a user_id (consistent with §9: the device is identified by its cert; the user is not exposed to it):
{
"decision": "allow",
"display_message": "Approved · SAR 50.00",
"product_reference": "wal_txn_889",
"status": "completed"
}
decision ∈ allow / deny / not_recognized. On authorize timeout or open circuit, the platform returns the linked service's configured fail_mode (default deny) — see §10.
Verification Response (POST /v1/challenges/{id}/complete):
{
"status": "completed",
"challenge_id": "ch_abc",
"user_id": "user_123",
"confidence": 0.9997,
"timestamp": "2026-02-25T10:00:00Z",
"metadata": {...}
}
Integrators receive the same metadata via webhooks (verification.complete, verification.failed).
Consent in API Responses: User-related endpoints (GET /v1/users/{id}, enrollment responses) include consent_status so integrators always know the current state without a separate API call.
Errors. All error responses follow {error: {code, message, details?}}. The full error-code catalog — platform HTTP errors, palm-vendor codes, and KYC/Nafath status — is in §15 (Error Reference).