Security API
The authenticated half of identity: MFA enrolment, passkeys, recovery codes, the session list, and the security event log. An API key authenticates but is refused — a key is a credential, not a person.
Updated
On this page
- GET /security/events
- GET /security/mfa
- POST /security/mfa/totp/setup
- POST /security/mfa/totp/confirm
- DELETE /security/mfa/totp
- GET /security/mfa/passkeys
- POST /security/mfa/passkeys/register/options
- POST /security/mfa/passkeys/register/verify
- PATCH /security/mfa/passkeys/{passkey}
- DELETE /security/mfa/passkeys/{passkey}
- GET /security/mfa/recovery_codes
- POST /security/mfa/recovery_codes
- PUT /security/password
- GET /security/sessions
- POST /security/sessions/revoke_others
- DELETE /security/sessions/{session}
16 operations, generated from
openapi/signclad.v1.yaml. Try them in the
interactive reference, browse
every endpoint group, or read the
guides for the prose version.
- GET
/security/eventsList security events - GET
/security/mfaGet MFA status - POST
/security/mfa/totp/setupStart authenticator enrolment - POST
/security/mfa/totp/confirmConfirm authenticator enrolment - DELETE
/security/mfa/totpRemove the authenticator - GET
/security/mfa/passkeysList passkeys - POST
/security/mfa/passkeys/register/optionsGet passkey creation options - POST
/security/mfa/passkeys/register/verifyFinish registering a passkey - PATCH
/security/mfa/passkeys/{passkey}Rename a passkey - DELETE
/security/mfa/passkeys/{passkey}Remove a passkey - GET
/security/mfa/recovery_codesCount remaining recovery codes - POST
/security/mfa/recovery_codesGenerate a new set of recovery codes - PUT
/security/passwordChange the password - GET
/security/sessionsList active sessions - POST
/security/sessions/revoke_othersSign out every other session - DELETE
/security/sessions/{session}Revoke one session
GET /security/events
List security events Extension
The person's own security log: sign-ins, failures, lockouts, MFA changes, passkeys,
sessions, password and email changes. Cursor-paginated, newest first.
Every route under /security requires a person. An API key authenticates and is then
refused 403: a key has no TOTP secret, no sessions, and no security log of its own. These
routes are also the one place exempt from the MFA-enrolment requirement — the only way to
enrol must not itself require enrolment.
- Base URL
https://api.signclad.com/api/v1- Authentication
- API key or OAuth 2.1 access token
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
type | string | Optional | One event type from the catalog below. |
limit | integer | Optional | |
cursor | string | Optional | Opaque cursor from a previous response's next_cursor. |
Responses
| Status | Description |
|---|---|
200 | A page of events. |
401 | Missing or invalid credentials. Unauthenticated requests are rate limited at 50 per minute.… |
403 | Authenticated, but not allowed to do this: an insufficient role, a credential type the route refuses, an unenrolled second factor, or a signer acting out of turn. meta.error always says which.… |
422 | Validation failed. errors maps a field name to a message string, or to an object keyed by an error code or by a per-item key. Values are never arrays. |
429 | Rate limited. The message contains the literal 429 Too Many Requests for compatibility with clients that match on it.… |
Example request
curl -X GET https://api.signclad.com/api/v1/security/events \
-H "X-Api-Key: $SIGNCLAD_API_KEY" GET /security/mfa
Get MFA status Extension
What second factors this person has, whether their role requires one, and how long they have to enrol. Also lists their passkeys and whether a TOTP enrolment is waiting to be confirmed.
- Base URL
https://api.signclad.com/api/v1- Authentication
- API key or OAuth 2.1 access token
Responses
| Status | Description |
|---|---|
200 | The status. |
401 | Missing or invalid credentials. Unauthenticated requests are rate limited at 50 per minute.… |
403 | Authenticated, but not allowed to do this: an insufficient role, a credential type the route refuses, an unenrolled second factor, or a signer acting out of turn. meta.error always says which.… |
Example request
curl -X GET https://api.signclad.com/api/v1/security/mfa \
-H "X-Api-Key: $SIGNCLAD_API_KEY" POST /security/mfa/totp/setup
Start authenticator enrolment Extension
Returns the shared secret in three forms — raw base32, an otpauth:// URI, and a rendered
QR code as inline SVG markup — plus the parameters an authenticator needs. Nothing is
enrolled until confirm succeeds.
- Base URL
https://api.signclad.com/api/v1- Authentication
- API key or OAuth 2.1 access token
Responses
| Status | Description |
|---|---|
200 | The enrolment material. |
401 | Missing or invalid credentials. Unauthenticated requests are rate limited at 50 per minute.… |
403 | Authenticated, but not allowed to do this: an insufficient role, a credential type the route refuses, an unenrolled second factor, or a signer acting out of turn. meta.error always says which.… |
422 | errors.totp reads An authenticator app is already set up. Remove it before adding another. |
Example request
curl -X POST https://api.signclad.com/api/v1/security/mfa/totp/setup \
-H "X-Api-Key: $SIGNCLAD_API_KEY" POST /security/mfa/totp/confirm
Confirm authenticator enrolment Extension
Proves the authenticator works and completes enrolment. recovery_codes is returned only
when this enrolment generated the person's first set — otherwise it is null and the
existing codes still stand.
- Base URL
https://api.signclad.com/api/v1- Authentication
- API key or OAuth 2.1 access token
Request body
application/json
| Property | Type | Required | Description |
|---|---|---|---|
code | string | Required |
Responses
| Status | Description |
|---|---|
200 | Enrolled. |
401 | Missing or invalid credentials. Unauthenticated requests are rate limited at 50 per minute.… |
403 | Authenticated, but not allowed to do this: an insufficient role, a credential type the route refuses, an unenrolled second factor, or a signer acting out of turn. meta.error always says which.… |
422 | errors.code reads That code is not valid.; errors.totp reads Start the setup again: there is no enrolment waiting to be confirmed. |
Example request
curl -X POST https://api.signclad.com/api/v1/security/mfa/totp/confirm \
-H "X-Api-Key: $SIGNCLAD_API_KEY" DELETE /security/mfa/totp
Remove the authenticator Extension
Takes a password in the body — unusual on a DELETE, and required whenever the account
has a password at all. Refused when the person's role requires a second factor and this is
their last one.
- Base URL
https://api.signclad.com/api/v1- Authentication
- API key or OAuth 2.1 access token
Request body
application/json
| Property | Type | Required | Description |
|---|---|---|---|
password | string or null | Optional | Required in practice whenever the account has a password. |
Responses
| Status | Description |
|---|---|
200 | Removed. |
401 | Missing or invalid credentials. Unauthenticated requests are rate limited at 50 per minute.… |
403 | Authenticated, but not allowed to do this: an insufficient role, a credential type the route refuses, an unenrolled second factor, or a signer acting out of turn. meta.error always says which.… |
422 | errors.password reads The current password is incorrect.; errors.totp reads Your role requires two-factor authentication. Add another factor before removing this one. |
Example request
curl -X DELETE https://api.signclad.com/api/v1/security/mfa/totp \
-H "X-Api-Key: $SIGNCLAD_API_KEY" GET /security/mfa/passkeys
List passkeys Extension
This person's registered passkeys, newest first.
- Base URL
https://api.signclad.com/api/v1- Authentication
- API key or OAuth 2.1 access token
Responses
| Status | Description |
|---|---|
200 | The passkeys. |
401 | Missing or invalid credentials. Unauthenticated requests are rate limited at 50 per minute.… |
403 | Authenticated, but not allowed to do this: an insufficient role, a credential type the route refuses, an unenrolled second factor, or a signer acting out of turn. meta.error always says which.… |
Example request
curl -X GET https://api.signclad.com/api/v1/security/mfa/passkeys \
-H "X-Api-Key: $SIGNCLAD_API_KEY" POST /security/mfa/passkeys/register/options
Get passkey creation options Extension
Returns the WebAuthn PublicKeyCredentialCreationOptions to hand to
navigator.credentials.create(), unwrapped at the top level. The object is passed
through from the WebAuthn library with null values omitted, so optional members are absent
rather than null and the exact key set follows that library rather than this document.
- Base URL
https://api.signclad.com/api/v1- Authentication
- API key or OAuth 2.1 access token
Responses
| Status | Description |
|---|---|
200 | The creation options, verbatim. |
401 | Missing or invalid credentials. Unauthenticated requests are rate limited at 50 per minute.… |
403 | Authenticated, but not allowed to do this: an insufficient role, a credential type the route refuses, an unenrolled second factor, or a signer acting out of turn. meta.error always says which.… |
422 | errors.passkeys reads You have reached the maximum number of passkeys. |
Example request
curl -X POST https://api.signclad.com/api/v1/security/mfa/passkeys/register/options \
-H "X-Api-Key: $SIGNCLAD_API_KEY" POST /security/mfa/passkeys/register/verify
Finish registering a passkey Extension
Verifies the attestation from navigator.credentials.create() and stores the passkey.
recovery_codes comes back only when this was the person's first second factor.
- Base URL
https://api.signclad.com/api/v1- Authentication
- API key or OAuth 2.1 access token
Request body
application/json
| Property | Type | Required | Description |
|---|---|---|---|
credential | object | Required | The credential the browser returned, forwarded verbatim. |
name | string | Required |
Responses
| Status | Description |
|---|---|
201 | Registered. |
401 | Missing or invalid credentials. Unauthenticated requests are rate limited at 50 per minute.… |
403 | Authenticated, but not allowed to do this: an insufficient role, a credential type the route refuses, an unenrolled second factor, or a signer acting out of turn. meta.error always says which.… |
422 | errors.credential reads The sign-in attempt expired. Start again. or That passkey could not be verified. |
Example request
curl -X POST https://api.signclad.com/api/v1/security/mfa/passkeys/register/verify \
-H "X-Api-Key: $SIGNCLAD_API_KEY" PATCH /security/mfa/passkeys/{passkey}
Rename a passkey Extension
Only the name can change. Ownership is checked before validation, so a passkey belonging to
somebody else is 404 even when the body is also invalid.
- Base URL
https://api.signclad.com/api/v1- Authentication
- API key or OAuth 2.1 access token
Path parameters
| Name | Type | Description |
|---|---|---|
passkey | string | The passkey's id. |
Request body
application/json
| Property | Type | Required | Description |
|---|---|---|---|
name | string | Required |
Responses
| Status | Description |
|---|---|
200 | Renamed. No mfa block here. |
401 | Missing or invalid credentials. Unauthenticated requests are rate limited at 50 per minute.… |
403 | Authenticated, but not allowed to do this: an insufficient role, a credential type the route refuses, an unenrolled second factor, or a signer acting out of turn. meta.error always says which.… |
404 | No such record for this workspace. Signclad never answers 404 for a record that exists: a 404 is authoritative. |
422 | Validation failed. errors maps a field name to a message string, or to an object keyed by an error code or by a per-item key. Values are never arrays. |
Example request
curl -X PATCH https://api.signclad.com/api/v1/security/mfa/passkeys/{passkey} \
-H "X-Api-Key: $SIGNCLAD_API_KEY" DELETE /security/mfa/passkeys/{passkey}
Remove a passkey Extension
No password re-authentication here, unlike removing an authenticator. Refused when the person's role requires a second factor and this is their last one.
- Base URL
https://api.signclad.com/api/v1- Authentication
- API key or OAuth 2.1 access token
Path parameters
| Name | Type | Description |
|---|---|---|
passkey | string | The passkey's id. |
Responses
| Status | Description |
|---|---|
200 | Removed. |
401 | Missing or invalid credentials. Unauthenticated requests are rate limited at 50 per minute.… |
403 | Authenticated, but not allowed to do this: an insufficient role, a credential type the route refuses, an unenrolled second factor, or a signer acting out of turn. meta.error always says which.… |
404 | No such record for this workspace. Signclad never answers 404 for a record that exists: a 404 is authoritative. |
422 | errors.passkey reads Your role requires two-factor authentication. Add another factor before removing this one. |
Example request
curl -X DELETE https://api.signclad.com/api/v1/security/mfa/passkeys/{passkey} \
-H "X-Api-Key: $SIGNCLAD_API_KEY" GET /security/mfa/recovery_codes
Count remaining recovery codes Extension
How many codes are left, and how many a fresh set contains. The codes themselves are never returned here.
- Base URL
https://api.signclad.com/api/v1- Authentication
- API key or OAuth 2.1 access token
Responses
| Status | Description |
|---|---|
200 | The counts. |
401 | Missing or invalid credentials. Unauthenticated requests are rate limited at 50 per minute.… |
403 | Authenticated, but not allowed to do this: an insufficient role, a credential type the route refuses, an unenrolled second factor, or a signer acting out of turn. meta.error always says which.… |
Example request
curl -X GET https://api.signclad.com/api/v1/security/mfa/recovery_codes \
-H "X-Api-Key: $SIGNCLAD_API_KEY" POST /security/mfa/recovery_codes
Generate a new set of recovery codes Extension
Replaces any existing codes and returns the new ones — the only time they are shown. Takes
password when the account has one.
- Base URL
https://api.signclad.com/api/v1- Authentication
- API key or OAuth 2.1 access token
Request body
application/json
| Property | Type | Required | Description |
|---|---|---|---|
password | string or null | Optional |
Responses
| Status | Description |
|---|---|
201 | The new codes. |
401 | Missing or invalid credentials. Unauthenticated requests are rate limited at 50 per minute.… |
403 | Authenticated, but not allowed to do this: an insufficient role, a credential type the route refuses, an unenrolled second factor, or a signer acting out of turn. meta.error always says which.… |
422 | errors.password reads The current password is incorrect. |
Example request
curl -X POST https://api.signclad.com/api/v1/security/mfa/recovery_codes \
-H "X-Api-Key: $SIGNCLAD_API_KEY" PUT /security/password
Change the password Extension
Revokes every other session and reports how many; the current session survives.
current_password is required whenever the account has one — a Google-only account has
none. The new password is checked against a breach corpus, so a long password can still be
refused.
- Base URL
https://api.signclad.com/api/v1- Authentication
- API key or OAuth 2.1 access token
Request body
application/json
| Property | Type | Required | Description |
|---|---|---|---|
password | string | Required | At least 12 characters and at most 72 bytes, checked against a breach corpus. A long password that appears in a known breach is refused with a 422, so length alone is not a guarantee the value will be accepted. |
current_password | string or null | Optional |
Responses
| Status | Description |
|---|---|
200 | Changed. |
401 | Missing or invalid credentials. Unauthenticated requests are rate limited at 50 per minute.… |
403 | Authenticated, but not allowed to do this: an insufficient role, a credential type the route refuses, an unenrolled second factor, or a signer acting out of turn. meta.error always says which.… |
422 | errors.current_password reads The current password is incorrect. |
Example request
curl -X PUT https://api.signclad.com/api/v1/security/password \
-H "X-Api-Key: $SIGNCLAD_API_KEY" GET /security/sessions
List active sessions Extension
Every signed-in session for this person, with the current one flagged, and the session policy.
- Base URL
https://api.signclad.com/api/v1- Authentication
- API key or OAuth 2.1 access token
Responses
| Status | Description |
|---|---|
200 | The sessions. |
401 | Missing or invalid credentials. Unauthenticated requests are rate limited at 50 per minute.… |
403 | Authenticated, but not allowed to do this: an insufficient role, a credential type the route refuses, an unenrolled second factor, or a signer acting out of turn. meta.error always says which.… |
Example request
curl -X GET https://api.signclad.com/api/v1/security/sessions \
-H "X-Api-Key: $SIGNCLAD_API_KEY" POST /security/sessions/revoke_others
Sign out every other session Extension
Keeps this session and revokes the rest. revoked is a count, as it is on
DELETE /security/sessions/{session}.
- Base URL
https://api.signclad.com/api/v1- Authentication
- API key or OAuth 2.1 access token
Responses
| Status | Description |
|---|---|
200 | How many were revoked. |
401 | Missing or invalid credentials. Unauthenticated requests are rate limited at 50 per minute.… |
403 | Authenticated, but not allowed to do this: an insufficient role, a credential type the route refuses, an unenrolled second factor, or a signer acting out of turn. meta.error always says which.… |
Example request
curl -X POST https://api.signclad.com/api/v1/security/sessions/revoke_others \
-H "X-Api-Key: $SIGNCLAD_API_KEY" DELETE /security/sessions/{session}
Revoke one session Extension
Revoking the current session is allowed, and was_current says whether that is what
happened. revoked counts what was revoked, the same as on revoke_others.
- Base URL
https://api.signclad.com/api/v1- Authentication
- API key or OAuth 2.1 access token
Path parameters
| Name | Type | Description |
|---|---|---|
session | string | The session's id. |
Responses
| Status | Description |
|---|---|
200 | Revoked. |
401 | Missing or invalid credentials. Unauthenticated requests are rate limited at 50 per minute.… |
403 | Authenticated, but not allowed to do this: an insufficient role, a credential type the route refuses, an unenrolled second factor, or a signer acting out of turn. meta.error always says which.… |
404 | No such record for this workspace. Signclad never answers 404 for a record that exists: a 404 is authoritative. |
Example request
curl -X DELETE https://api.signclad.com/api/v1/security/sessions/{session} \
-H "X-Api-Key: $SIGNCLAD_API_KEY"