---
title: "Validate a signer enrollment"
method: POST
path: "/v1/multisig-wallets/{walletId}/signers/{signerId}/validation"
tags: ["Multisig Wallets"]
---

# Validate a signer enrollment

`POST /v1/multisig-wallets/{walletId}/signers/{signerId}/validation`

## Request

- Base URL: `https://api.prod.keyban.io`
- URL: `https://api.prod.keyban.io/v1/multisig-wallets/{walletId}/signers/{signerId}/validation`
- Auth: one of:
  - API key in header `X-Api-Key`
  - `bearer` (a scheme the document does not define)

Confirm a pending enrollment with the 4-digit code read off the
candidate's phone. Only a signer already on the wallet can validate, and
the enrollment must have been challenged and revealed first.

What this catches: a candidate identity substituted between the two
phones, and plain human error — the API withholds the identity of a
`requested` enrollment precisely so the code cannot be read off a screen
instead of the other phone, and the engagement–reveal keeps the short
code from being ground: a wrong code **burns** the enrollment.
What it does **not** catch: a signer who is themselves the attacker. One
validation admits a key, so a single compromised signer can grow the set
with keys they control. Raising the admission quorum and notifying every
signer on each validation are tracked as hardening.

## Path parameters

- `walletId` string, uuid, required
- `signerId` string, uuid, required

## Request body

- ValidateMultisigSignerDto
  - `code` string, required: Four-digit SAS read off the candidate phone and compared out of band. A wrong code **burns** the enrollment (status `failed`): the short code buys a single online guess, not an offline search.

## Response `200`

Enrollment validated

- MultisigSignerDtoOutput
  - `id` string, uuid, required: Entity UUID
  - `createdAt` string, date-time, required: Creation date (ISO 8601)
  - `updatedAt` string, date-time, required: Last update date (ISO 8601)
  - `status` 'requested' | 'validated' | 'active' | 'failed', required: Enrollment status: `requested` (address bound, awaiting a peer validation), `validated` (counts towards the threshold), `active` (in the on-chain signer set, can sign), `failed` (on-chain add exhausted its retries).
  - `user` object, nullable, required: Organization member holding the TSS signing key. Null only when the user reference could not be populated.
    - `id` string, uuid, required: User ID of the signer.
    - `name` string, required: Display name of the signer, as set on their user profile.
    - `email` string, email, required: Email address of the signer.
    - `image` string, nullable, required: Avatar URL of the signer (from their sign-in provider); null without one.
  - `signerType` 'eoa' | 'webauthn', required: Kind of key behind this signer: `eoa` (20-byte secp256k1 address) or `webauthn` (84-byte P-256 passkey signer). Derived from the identity, never stored.
  - `address` string, nullable: ERC-7913 identity of the signing key: a 20-byte EVM address for an `eoa` signer, the 84-byte `verifier ‖ qx ‖ qy` bytes for a `webauthn` one. **Withheld while `requested`**: the SAS a validator must type derives from it, so serving it here would let any client compute the code instead of reading it off the candidate's phone — the whole point of the comparison. Revealed once validated.
  - `validatorNonce` string, nullable: The challenge nonce, once a validator has challenged this enrollment. The candidate app reads it to derive the 4-digit SAS it displays; null before a challenge and after the ceremony settles.
  - `validatedAt` string, date-time, nullable, required: When a peer validated this enrollment. Null while requested.

## Other responses

- `403`: Caller is not a signer of this wallet
- `404`: Multisig wallet or enrollment not found
- `409`: The enrollment is not awaiting validation, or was not challenged
- `422`: Wrong code — the enrollment is burned

---

[API](https://skmtc.dev/keyban/apis/keyban-rest-apis.md) · [All operations](https://skmtc.dev/keyban/apis/keyban-rest-apis/llms.txt) · [OpenAPI document](https://skmtc.dev/keyban/apis/keyban-rest-apis/revisions/0bb79a1da961?raw)
