Confirm Signing Credential
Completes a key registration started by Init Signing Credential. Your backend sends the registration proof produced by the SDK's createRegistrationProof; on success the device key becomes an ACTIVE signing credential of the device, and the response — the registration result — goes back to the SDK's activateCredential.
Endpoint
POST /v1/signing-credential/confirm
Content-Type: application/json
Device-Model: Pixel 8
Os-Version: 15
Platform: android
Sdk-Version: 1.4.0{
"device_id": "device_00000001",
"key_id": "<KEY_ID>",
"proof": "<REGISTRATION_PROOF>"
}Parameters:
| Param | Type | Required | Default | Description |
|---|---|---|---|---|
device_id | string | Yes | — | The device_id sent to Init. Same rules: not blank, no leading or trailing whitespace, at most 128 characters. |
key_id | string | Yes | — | The key_id returned by Init. |
proof | string | Yes | — | The compact JWS returned by the SDK's createRegistrationProof. Forward it unchanged. |
Headers:
Besides the authentication headers, send the device information the SDK reports. The values are trimmed and stored with the credential as informational metadata, which Get Active Signing Credential returns. They are stored as sent, not normalised.
| Header | Required | Description |
|---|---|---|
Device-Model | No | Device model, e.g. Pixel 8. |
Os-Version | No | OS version, e.g. 15. |
Platform | No | ios or android (case-insensitive). Also selects how the key attestation is labelled. |
Sdk-Version | No | FaceAuthen SDK version, e.g. 1.4.0. |
Returns: ConfirmSigningCredentialResponse
Call it before the expires_at returned by Init. On Android the proof carries the key's attestation chain; a missing or unverifiable chain does not fail the call — the credential is stored with key_attestation: NONE.
Sample Request
curl --location '<BASE_URL>/v1/signing-credential/confirm' \
--header 'Authorization: ATV <ACCESS_ID>:<SIGNATURE>' \
--header 'X-TV-Timestamp: <TIMESTAMP>' \
--header 'Content-Type: application/json' \
--header 'Device-Model: Pixel 8' \
--header 'Os-Version: 15' \
--header 'Platform: android' \
--header 'Sdk-Version: 1.4.0' \
--data '{
"device_id": "device_00000001",
"key_id": "<KEY_ID>",
"proof": "<REGISTRATION_PROOF>"
}'Response
{
"success": true,
"code": 0,
"message": "Success",
"data": {
"request_id": "f48085e4-3ae4-40bb-b0e1-9b2c72575bc1",
"key_id": "<KEY_ID>",
"key_thumbprint": "NzbLsXh8uDCcd-6MNwXF4W_7noWXFZAfHkxZsRGC9Xs",
"status": "ACTIVE"
},
"errors": []
}| Field | Type | Description |
|---|---|---|
data.request_id | string | The request ID, used for tracing. |
data.key_id | string | The confirmed key ID — the key_id from Init. The SDK sends it in X-Device-Key-Id. |
data.key_thumbprint | string | RFC 7638 thumbprint of the registered public key. |
data.status | string | ACTIVE on first confirmation; the credential's current status on a retry. |
errors | array | Detail of each failure. Empty on success. |
Forward key_id, key_thumbprint and status to the SDK as the registration result without changing any value.
- Retries are safe. Repeating the call for an already confirmed registration returns the original result and never creates a second credential.
- Every confirmation adds a key. A device can hold any number of ACTIVE keys: each successful Confirm adds a new one, and earlier keys stay ACTIVE until you revoke them with Revoke Signing Credential.
- A failed call leaves the device's existing keys unchanged.
WARNING
Call this endpoint from your backend only, with your Access Key. The SDK's Bearer token is rejected with 403101.
Errors
| Code | Message |
|---|---|
2001010 | Access ID not found in the system. |
2009000 | Registration not found or expired. |
2009001 | Registration proof is invalid. |
2009003 | Another registration for this key is in progress. Please retry. |
401100 | Unauthorized action. You do not have permission to perform this action. |
403101 | Permission denied. You do not have permission to perform this action. |
4001000 | Input parameter violates a constraint. |
4001001 | The X-TV-Timestamp header is expired. Please provide a newer timestamp. |
5001000 | Some unexpected error occurs while processing the request. |
| Code | Description |
|---|---|
access_id_not_found | Access ID not found in the system. |
registration_expired | The key_id is unknown, belongs to another device, or passed expires_at. Start again with Init. |
registration_proof_invalid | The proof failed a check. detail.reason names it, e.g. proof_signature_invalid, proof_challenge_mismatch, key_already_registered. |
registration_conflict | A concurrent confirmation for the same key_id is running. Safe to retry. |
access_denied_exception | Missing or invalid Access Key or signature. |
permission_denied_exception | Called with an SDK Bearer token; only the Access Key is allowed. |
invalid_parameter_exception | device_id is missing, blank, longer than 128 characters, or starts or ends with whitespace; or key_id or proof is missing. |
request_time_too_skewed | The X-TV-Timestamp header is expired, need a newer one. |
internal_server_error | Some unexpected error occurs while processing the request. |
Next Steps
- Get Active Signing Credential — list the device's ACTIVE keys
- Revoke Signing Credential — revoke a key when a phone is lost