Reference

Mobile endpoints

Generated from the OpenAPI document. Read the device API guide first for the activation flow and the request-signing algorithm; this page is the field-level detail.

Preview

See availability: device activation is not yet possible in production.

Device endpoints (17)#

GET /api/v1/mobile/health #

Device API liveness

Public — no authentication operationId mobileHealth

Unauthenticated liveness endpoint. Reports the API version and Play Integrity mode.

Responses

StatusMeaningSchema
200 Service healthy MobileEnvelope
default Error response MobileError

POST /api/v1/mobile/activation/start #

Redeem a pairing code and register a device key

Pairing code + device challenge — no token yet operationId startMobileActivation

Consumes a single-use 8-character Crockford pairing code, validates the Ed25519 public key and Play Integrity verdict, creates a PENDING device and returns a 5-minute signature challenge. Rate limited to 10 requests per minute per IP. In live Play Integrity mode the token must be issued within the last 10 minutes and must carry requestHash set to the lowercase hex SHA-256 of the exact publicKeyPem string sent in this request; otherwise activation is refused.

Request body · ActivationStartRequest (application/json)

FieldTypeDetails
pairingCode required string
clientRequestId string (uuid)
publicKeyPem required string Ed25519 public key in SPKI PEM form.
playIntegrityToken required string
device object
device.label string max length 120
device.manufacturer string
device.model string
device.androidVersion string
device.appVersion string
device.scanner object
device.scanner.vendor string
device.scanner.model string
device.scanner.serialHash string
device.scanner.firmware string
device.scanner.sdkVersion string

Responses

StatusMeaningSchema
201 Successful response MobileEnvelope
default Error response MobileError

POST /api/v1/mobile/activation/complete #

Prove key possession and receive device tokens

Pairing code + device challenge — no token yet operationId completeMobileActivation

Verifies the Ed25519 signature over deviceId.challenge.tenantId.userId and issues an opaque access token, refresh token and 14-day lease.

Request body · ActivationCompleteRequest (application/json)

FieldTypeDetails
activationId required string
signature required string Base64url Ed25519 signature over deviceId.challenge.tenantId.userId.

Responses

StatusMeaningSchema
200 Successful response MobileEnvelope
default Error response MobileError

POST /api/v1/mobile/auth/refresh #

Rotate the device refresh token

Signed request — no access token operationId refreshMobileToken

Signature-only authentication. The previous refresh token is invalidated and the device lease is renewed. Allowed after the access token and lease have expired. Idempotent: send a stable clientRequestId. A replay returns HTTP 200 with data.idempotentReplay = true.

Requires the five X-RR-* signing headers — how to sign a request.

Request body (application/json)

FieldTypeDetails
refreshToken required string

Responses

StatusMeaningSchema
200 Successful response MobileEnvelope
default Error response MobileError

POST /api/v1/mobile/auth/revoke #

Self-revoke the device

Device bearer token + signed request Signed request headers operationId revokeMobileDevice

Marks the device REVOKED and invalidates all access tokens. Idempotent: send a stable clientRequestId. A replay returns HTTP 200 with data.idempotentReplay = true.

Requires the five X-RR-* signing headers — how to sign a request.

Responses

StatusMeaningSchema
200 Successful response MobileEnvelope
default Error response MobileError

GET /api/v1/mobile/config #

Device configuration

Device bearer token + signed request Signed request headers operationId getMobileConfig

Tenant thresholds, scanner allowlist, offline policy and retention settings.

Requires the five X-RR-* signing headers — how to sign a request.

Responses

StatusMeaningSchema
200 Successful response MobileEnvelope
default Error response MobileError

GET /api/v1/mobile/roster #

Assigned learner roster

Device bearer token + signed request Signed request headers operationId getMobileRoster

Returns only learners in the cohorts assigned to the device. The response carries an ETag for conditional requests.

Requires the five X-RR-* signing headers — how to sign a request.

Responses

StatusMeaningSchema
200 Successful response MobileEnvelope
default Error response MobileError

GET /api/v1/mobile/sessions #

Scheduled sessions and venues

Device bearer token + signed request Signed request headers operationId getMobileSessions

Sessions for the next 14 days derived from assigned cohort schedules and venues.

Requires the five X-RR-* signing headers — how to sign a request.

Responses

StatusMeaningSchema
200 Successful response MobileEnvelope
default Error response MobileError

POST /api/v1/mobile/enrolments #

Enrol ISO/IEC 19794-2 fingerprint templates

Device bearer token + signed request Signed request headers operationId enrolMobileBiometrics

Accepts 1–4 minutiae templates. The server validates format, size, NFIQ2 and minutiae count, rejects duplicate templates enrolled to another learner, and stores only a SHA-256 template hash. No image or raw template is retained. Requires recorded POPIA consent and the learner M1 biometric preference. Idempotent: send a stable clientRequestId. A replay returns HTTP 200 with data.idempotentReplay = true.

Requires the five X-RR-* signing headers — how to sign a request.

Request body · EnrolmentRequest (application/json)

FieldTypeDetails
learnerId required string
consentRef required string min length 6
clientRequestId required string (uuid)
scannerSerialHash string
fingers required array<object> min items 1; max items 4
fingers[].position required enum one of "RIGHT_THUMB", "RIGHT_INDEX", "LEFT_THUMB", "LEFT_INDEX", "RIGHT_MIDDLE", "LEFT_MIDDLE"
fingers[].templateFormat required const "ISO_19794_2_2005"
fingers[].templateBase64 required string ISO/IEC 19794-2 template, 64–4096 bytes when decoded.
fingers[].nfiq2Score required integer min 50; max 100
fingers[].minutiaeCount required integer min 12; max 120
fingers[].capturedAt string (date-time)

Responses

StatusMeaningSchema
201 Successful response MobileEnvelope
default Error response MobileError

POST /api/v1/mobile/match #

Bounded 1:1 or scoped 1:N fingerprint match

Device bearer token + signed request Signed request headers operationId matchMobileBiometrics

ONE_TO_MANY searches only the device’s assigned cohorts and venues. A no-match response contains no candidate list. Probe templates are never stored.

Requires the five X-RR-* signing headers — how to sign a request.

Request body · MatchRequest (application/json)

FieldTypeDetails
mode required enum one of "ONE_TO_ONE", "ONE_TO_MANY"
candidateLearnerId string Required for ONE_TO_ONE.
scope object
scope.cohortId string
scope.venueId string
fusion boolean
probes required array<object> min items 1; max items 2
probes[].position required enum one of "RIGHT_THUMB", "RIGHT_INDEX", "LEFT_THUMB", "LEFT_INDEX", "RIGHT_MIDDLE", "LEFT_MIDDLE"
probes[].templateFormat required const "ISO_19794_2_2005"
probes[].templateBase64 required string ISO/IEC 19794-2 template, 64–4096 bytes when decoded.
probes[].nfiq2Score required integer min 50; max 100
probes[].minutiaeCount required integer min 12; max 120
probes[].capturedAt string (date-time)

Responses

StatusMeaningSchema
200 Successful response MobileEnvelope
default Error response MobileError

POST /api/v1/mobile/attendance/events #

Submit one online attendance event

Device bearer token + signed request Signed request headers operationId submitMobileAttendanceEvent

Validates the geofence, applies the existing attendance ledger rules and records the event. Retries with the same clientRequestId return the original result with idempotentReplay = true. Idempotent: send a stable clientRequestId. A replay returns HTTP 200 with data.idempotentReplay = true.

Requires the five X-RR-* signing headers — how to sign a request.

Request body · AttendanceEventRequest (application/json)

FieldTypeDetails
eventId required string (uuid)
clientRequestId required string (uuid)
learnerId required string
method required enum one of "M1_BIOMETRIC_1N", "M2_BIOMETRIC_11", "M4_PIN_PHOTO", "M6_SUPERVISED_OVERRIDE"
occurredAt required string (date-time)
cohortId required string
venueId required string
sessionId string
matchId string
scannerSerialHash string
geofence object
geofence.lat number
geofence.lng number
geofence.accuracyM number
geofence.inside boolean
geofence.distanceM number
quality object
quality.nfiq2Score integer
flags object
flags.mockLocation boolean
flags.rooted boolean
flags.usbReplug boolean
flags.clockDrift boolean

Responses

StatusMeaningSchema
201 Successful response MobileEnvelope
default Error response MobileError

POST /api/v1/mobile/sync/batches #

Upload an offline attendance batch

Device bearer token + signed request Signed request headers operationId syncOfflineBatch

Verifies the device hash chain and Ed25519 batch signature, enforces a strict deviceSeq, and accepts or rejects each event independently. Gaps and chain mismatches fail the batch. Idempotent: send a stable clientRequestId. A replay returns HTTP 200 with data.idempotentReplay = true.

Requires the five X-RR-* signing headers — how to sign a request.

Request body · SyncBatchRequest (application/json)

FieldTypeDetails
batchId required string (uuid)
deviceSeq required integer min 1
previousBatchHash string
batchHash required string pattern ^[a-f0-9]{64}$
signature required string Base64url Ed25519 signature over batchHash.
capturedFrom string (date-time)
capturedTo string (date-time)
events required array<object> min items 1
events[].eventId required string (uuid)
events[].clientRequestId required string (uuid)
events[].learnerId required string
events[].method required enum one of "M1_BIOMETRIC_1N", "M2_BIOMETRIC_11", "M4_PIN_PHOTO", "M6_SUPERVISED_OVERRIDE"
events[].occurredAt required string (date-time)
events[].cohortId required string
events[].venueId required string
events[].sessionId string
events[].matchId string
events[].scannerSerialHash string
events[].geofence object
events[].geofence.lat number
events[].geofence.lng number
events[].geofence.accuracyM number
events[].geofence.inside boolean
events[].geofence.distanceM number
events[].quality object
events[].quality.nfiq2Score integer
events[].flags object
events[].flags.mockLocation boolean
events[].flags.rooted boolean
events[].flags.usbReplug boolean
events[].flags.clockDrift boolean

Responses

StatusMeaningSchema
200 Successful response MobileEnvelope
default Error response MobileError

GET /api/v1/mobile/sync/state #

Upload cursor state

Device bearer token + signed request Signed request headers operationId getMobileSyncState

Returns the last accepted device sequence, batch hash and lease state.

Requires the five X-RR-* signing headers — how to sign a request.

Responses

StatusMeaningSchema
200 Successful response MobileEnvelope
default Error response MobileError

POST /api/v1/mobile/heartbeat #

Record device health

Device bearer token + signed request Signed request headers operationId recordMobileHeartbeat

Battery, storage, scanner and app version. Allowed while a wipe is pending so the device can acknowledge it. Idempotent: send a stable clientRequestId. A replay returns HTTP 200 with data.idempotentReplay = true.

Requires the five X-RR-* signing headers — how to sign a request.

Request body · HeartbeatRequest (application/json)

FieldTypeDetails
batteryPct integer min 0; max 100
storageFreeMb integer min 0
appVersion string
scannerStatus string
pendingBatches integer min 0

Responses

StatusMeaningSchema
200 Successful response MobileEnvelope
default Error response MobileError

POST /api/v1/mobile/telemetry #

Submit non-PII diagnostics

Device bearer token + signed request Signed request headers operationId submitMobileTelemetry

Operational diagnostics with no learner identifiers or biometric data. Idempotent: send a stable clientRequestId. A replay returns HTTP 200 with data.idempotentReplay = true.

Requires the five X-RR-* signing headers — how to sign a request.

Responses

StatusMeaningSchema
200 Successful response MobileEnvelope
default Error response MobileError

POST /api/v1/mobile/evidence/upload-url #

Create a signed evidence upload URL

Device bearer token + signed request Signed request headers operationId createEvidenceUploadUrl

Returns an HMAC-signed, short-lived upload URL for non-biometric evidence. Returns 501 when no evidence store is configured. Idempotent: send a stable clientRequestId. A replay returns HTTP 200 with data.idempotentReplay = true.

Requires the five X-RR-* signing headers — how to sign a request.

Request body (application/json)

FieldTypeDetails
contentType required enum one of "image/jpeg", "image/png", "application/pdf"
byteLength required integer min 1; max 10485760
learnerId string
sessionId string

Responses

StatusMeaningSchema
200 Successful response MobileEnvelope
default Error response MobileError

POST /api/v1/mobile/wipe/ack #

Acknowledge a remote wipe

Device bearer token + signed request Signed request headers operationId acknowledgeMobileWipe

Confirms that local roster, templates and cached evidence have been removed. Idempotent: send a stable clientRequestId. A replay returns HTTP 200 with data.idempotentReplay = true.

Requires the five X-RR-* signing headers — how to sign a request.

Responses

StatusMeaningSchema
200 Successful response MobileEnvelope
default Error response MobileError

Administration endpoints (6)#

Used by tenant administrators (in the console) to issue pairing codes and to revoke or wipe devices. They require an administrator session and a tenant-administrator role, not device credentials.

GET /api/v1/mobile/admin/pairing-codes #

List pairing codes

Administrator session operationId listPairingCodes

Tenant-scoped pairing codes. Only the HMAC hash is stored; the plaintext code is shown once at creation.

Responses

StatusMeaningSchema
200 Pairing codes MobileEnvelope
default Error response MobileError

POST /api/v1/mobile/admin/pairing-codes #

Create a pairing code

Administrator session operationId createPairingCode

Creates a single-use 15-minute pairing code bound to a tenant and optionally to cohorts and venues. Roles: R1, R2, R3, R6.

Request body (application/json)

FieldTypeDetails
label string max length 120
cohortIds array<string>
venueIds array<string>

Responses

StatusMeaningSchema
201 Pairing code created MobileEnvelope
default Error response MobileError

DELETE /api/v1/mobile/admin/pairing-codes/{id} #

Revoke a pairing code

Administrator session operationId revokePairingCode

Revokes an unused pairing code. Roles: R1, R2, R3, R6.

Parameters

NameInTypeDescription
id required path string

Responses

StatusMeaningSchema
200 Pairing code revoked MobileEnvelope
default Error response MobileError

GET /api/v1/mobile/admin/devices #

List registered devices

Administrator session operationId listMobileDevices

Tenant-scoped device inventory with status, lease and last-seen metadata. Roles: R1, R2, R3, R6.

Responses

StatusMeaningSchema
200 Device inventory MobileEnvelope
default Error response MobileError

POST /api/v1/mobile/admin/devices/{id}/revoke #

Revoke a device

Administrator session operationId revokeMobileDeviceAdmin

Immediately invalidates tokens and blocks all device calls. Roles: R1, R2.

Parameters

NameInTypeDescription
id required path string

Responses

StatusMeaningSchema
200 Device revoked MobileEnvelope
default Error response MobileError

POST /api/v1/mobile/admin/devices/{id}/wipe #

Request a remote wipe

Administrator session operationId requestMobileDeviceWipe

Sets a wipe instruction; the device confirms through /mobile/wipe/ack. Roles: R1, R2.

Parameters

NameInTypeDescription
id required path string

Responses

StatusMeaningSchema
200 Wipe requested MobileEnvelope
default Error response MobileError