# Create signer

Invite a signer and receive a registration token, available only in the creation response or its short-lived replay. The signer provides its own name and keys when it registers. The invitation deadline limits its first use. If an unused invitation expires, delete it and create a new one. If registration succeeds but setup is interrupted, the same signer can retry with the original token even after the deadline, until the signer is deleted.
By default, a workspace can have up to 10 registered signers and unexpired invitations in total. Registered signers count even when offline. Expired unused invitations and deleted signers do not count. When the limit is reached, the request returns 429 with code signer.limit_exceeded and max set to the effective workspace limit.
Reuse the same Idempotency-Key with the same parameters when retrying this request. Current access is checked on every retry. The original response, including the token, can be returned for 60 seconds after successful creation, while the invitation is unused, unexpired and not deleted. Retries do not extend this window. Once the window closes or the invitation is used, the response returns 409 idempotency_result_expired without creating another invitation or revealing its token. Concurrent requests with the same key return 409 idempotency_in_progress and changed parameters return idempotency_request_mismatch. Missing, invalid or repeated headers return 400.

Endpoint: POST /signers
Version: 1.0.0
Security: Auth

## Security:

  - `Auth` (unknown)
    apiKey in header X-Api-Key scopes: vks:access

## Header parameters:

  - `Idempotency-Key` (string, required)
    Case-sensitive opaque key for one mutation intent. Send exactly one header occurrence containing 1 to 128 visible ASCII bytes (0x21..0x7e). Commas are literal data; do not trim, lowercase or require UUID syntax. Reuse the same key for retries, with current authorization checked on every attempt. Repeated header occurrences are rejected.

## Request fields (application/json):

  - `expires_at` (string)
    Deadline for first use of the invitation. Choose a future time within the allowed invitation period, or omit to use the default.

## Request examples:

  - `Invite a signer with the default registration period` (unknown)

  - `Invite a signer with a chosen registration deadline` (unknown)
    Choose a future time within the allowed invitation period before submitting.

## Response 201:

  - `201` (unknown)
    Pending signer and registration token. The same response may be replayed within the 60-second window.

## Response 201 fields (application/json):

  - `item` (object, required)
    A signer node, including its registration status and connection details.

  - `item.signer_id` (string, required)
    Unique identifier of the signer.

  - `item.name` (string)
    Name set on the signer. Appears once the signer provides it during registration.

  - `item.identity_fingerprint` (string)
    SHA-256 fingerprint of the decoded public key bytes. Use it to compare and verify the key.

  - `item.identity_public_key` (string)
    Ed25519 public key used to verify the signer identity. Raw key bytes encoded in Base64. Available after registration.

  - `item.encryption_public_key` (string)
    X25519 public key used to encrypt messages to the signer. Raw key bytes encoded in Base64. Available after registration.

  - `item.backend_descriptors` (array, required)
    Signing methods supported by the node. Empty until it connects for the first time.

  - `item.backend_descriptors.suite` (string, required)
    Signing protocol supported by the node.

  - `item.backend_descriptors.curve` (string, required)
    Cryptographic curve used by this signing method.

  - `item.backend_descriptors.backend` (string, required)
    Signing software used by the node.

  - `item.backend_descriptors.version` (string, required)
    Version of the signing software.

  - `item.registered_at` (string)
    Time the signer completed registration. Absent before registration.

  - `item.last_seen_at` (string)
    Time of the last known confirmed contact with the signer. Updates may be delayed. Absent until the first contact after registration.

  - `item.state` (string, required)
    Registration status of the signer.
    Enum: "pending", "registered", "expired"

  - `item.expires_at` (string)
    Deadline for first use of the invitation. Absent after the signer registers.

  - `token` (string, required)
    Registration token. Save it securely and pass it unchanged to the signer. It is available in the creation response and, for 60 seconds after creation, a replay with the same Idempotency-Key while the invitation is unused, unexpired and not deleted. Other endpoints never return it. If registration succeeds but setup is interrupted, the same signer can retry registration with the token it already received even after the invitation expires, until the signer is deleted.

## Response 400:

  - `400` (unknown)
    Some request values are missing or invalid. Check fields for details.

## Response 400 fields (application/problem+json):

  - `type` (string, required)
    A URI that identifies the error type.
    Example: https://docs.vilna.io/apis/errors#internal-error

  - `title` (string, required)
    A short summary of the error type.
Use `detail` for information specific to this occurrence.
    Example: Bad Request

  - `status` (integer, required)
    The HTTP status code for this error.
Matches the status code of the HTTP response.
    Example: 400

  - `detail` (string)
    A human-readable explanation of what went wrong in this specific case.
May be localized.
    Example: The address is already assigned to another invoice

  - `instance` (string)
    A URI that identifies this specific error occurrence.
Include this value when contacting support.
    Example: /traces/0123456789abcdef0123456789abcdef

  - `code` (string, required)
    Stable machine-readable error code for programmatic error handling. Unlike the HTTP `status` or free-form `detail`, this code is guaranteed not to change between versions for a given error condition, so it is safe to branch on in client code. Defaults to `unspecified` when the server has not assigned a specific code.
    Example: blockchain.not_found

  - `fields` (array)
    List of invalid fields in the request.

  - `fields.name` (string, required)
    The name of the invalid field.
    Example: max_len

  - `fields.reason` (string, required)
    Why this field is invalid.
    Example: 32

## Response 401:

  - `401` (unknown)
    Authentication is required to make this request.

## Response 401 fields (application/problem+json):

  - `type` (string, required)
    A URI that identifies the error type.
    Example: https://docs.vilna.io/apis/errors#internal-error

  - `title` (string, required)
    A short summary of the error type.
Use `detail` for information specific to this occurrence.
    Example: Bad Request

  - `status` (integer, required)
    The HTTP status code for this error.
Matches the status code of the HTTP response.
    Example: 400

  - `detail` (string)
    A human-readable explanation of what went wrong in this specific case.
May be localized.
    Example: The address is already assigned to another invoice

  - `instance` (string)
    A URI that identifies this specific error occurrence.
Include this value when contacting support.
    Example: /traces/0123456789abcdef0123456789abcdef

  - `code` (string, required)
    Stable machine-readable error code for programmatic error handling. Unlike the HTTP `status` or free-form `detail`, this code is guaranteed not to change between versions for a given error condition, so it is safe to branch on in client code. Defaults to `unspecified` when the server has not assigned a specific code.
    Example: blockchain.not_found

## Response 403:

  - `403` (unknown)
    You do not have permission to access VKS in this workspace.

## Response 403 fields (application/problem+json):

  - `type` (string, required)
    A URI that identifies the error type.
    Example: https://docs.vilna.io/apis/errors#internal-error

  - `title` (string, required)
    A short summary of the error type.
Use `detail` for information specific to this occurrence.
    Example: Bad Request

  - `status` (integer, required)
    The HTTP status code for this error.
Matches the status code of the HTTP response.
    Example: 400

  - `detail` (string)
    A human-readable explanation of what went wrong in this specific case.
May be localized.
    Example: The address is already assigned to another invoice

  - `instance` (string)
    A URI that identifies this specific error occurrence.
Include this value when contacting support.
    Example: /traces/0123456789abcdef0123456789abcdef

  - `code` (string, required)
    Stable machine-readable error code for programmatic error handling. Unlike the HTTP `status` or free-form `detail`, this code is guaranteed not to change between versions for a given error condition, so it is safe to branch on in client code. Defaults to `unspecified` when the server has not assigned a specific code.
    Example: blockchain.not_found

## Response 409:

  - `409` (unknown)
    The request conflicts with the current resource state.

## Response 409 fields (application/problem+json):

  - `type` (string, required)
    A URI that identifies the error type.
    Example: https://docs.vilna.io/apis/errors#internal-error

  - `title` (string, required)
    A short summary of the error type.
Use `detail` for information specific to this occurrence.
    Example: Bad Request

  - `status` (integer, required)
    The HTTP status code for this error.
Matches the status code of the HTTP response.
    Example: 400

  - `detail` (string)
    A human-readable explanation of what went wrong in this specific case.
May be localized.
    Example: The address is already assigned to another invoice

  - `instance` (string)
    A URI that identifies this specific error occurrence.
Include this value when contacting support.
    Example: /traces/0123456789abcdef0123456789abcdef

  - `code` (string, required)
    Stable machine-readable error code for programmatic error handling. Unlike the HTTP `status` or free-form `detail`, this code is guaranteed not to change between versions for a given error condition, so it is safe to branch on in client code. Defaults to `unspecified` when the server has not assigned a specific code.
    Example: blockchain.not_found

## Response 429:

  - `429` (unknown)
    Resource quota exceeded. The response includes the effective limit for this scope. The applicable code and limit depend on the operation; examples illustrate different limits.

## Response 429 fields (application/problem+json):

  - `type` (string, required)
    A URI that identifies the error type.
    Example: https://docs.vilna.io/apis/errors#internal-error

  - `title` (string, required)
    A short summary of the error type.
Use `detail` for information specific to this occurrence.
    Example: Bad Request

  - `status` (integer, required)
    The HTTP status code for this error.
Matches the status code of the HTTP response.
    Example: 400

  - `detail` (string)
    A human-readable explanation of what went wrong in this specific case.
May be localized.
    Example: The address is already assigned to another invoice

  - `instance` (string)
    A URI that identifies this specific error occurrence.
Include this value when contacting support.
    Example: /traces/0123456789abcdef0123456789abcdef

  - `code` (string, required)
    Stable machine-readable code identifying the exhausted resource quota. The code is always
supplied by the service; clients branch on it instead of the human-readable detail.
    Example: address.quota_exceeded

  - `max` (integer, required)
    Effective maximum for this resource in the caller's scope. Zero prohibits new admissions;
it does not disable resources already held. This is the configured limit, not current usage.
    Example: 100

## Response 503:

  - `503` (unknown)
    The service is temporarily unavailable. Try again later.

## Response 503 fields (application/problem+json):

  - `type` (string, required)
    A URI that identifies the error type.
    Example: https://docs.vilna.io/apis/errors#internal-error

  - `title` (string, required)
    A short summary of the error type.
Use `detail` for information specific to this occurrence.
    Example: Bad Request

  - `status` (integer, required)
    The HTTP status code for this error.
Matches the status code of the HTTP response.
    Example: 400

  - `detail` (string)
    A human-readable explanation of what went wrong in this specific case.
May be localized.
    Example: The address is already assigned to another invoice

  - `instance` (string)
    A URI that identifies this specific error occurrence.
Include this value when contacting support.
    Example: /traces/0123456789abcdef0123456789abcdef

  - `code` (string, required)
    Stable machine-readable error code for programmatic error handling. Unlike the HTTP `status` or free-form `detail`, this code is guaranteed not to change between versions for a given error condition, so it is safe to branch on in client code. Defaults to `unspecified` when the server has not assigned a specific code.
    Example: blockchain.not_found

## Response default:

  - `default` (unknown)
    Details of an error that prevented the request from completing.

## Response default fields (application/problem+json):

  - `type` (string, required)
    A URI that identifies the error type.
    Example: https://docs.vilna.io/apis/errors#internal-error

  - `title` (string, required)
    A short summary of the error type.
Use `detail` for information specific to this occurrence.
    Example: Bad Request

  - `status` (integer, required)
    The HTTP status code for this error.
Matches the status code of the HTTP response.
    Example: 400

  - `detail` (string)
    A human-readable explanation of what went wrong in this specific case.
May be localized.
    Example: The address is already assigned to another invoice

  - `instance` (string)
    A URI that identifies this specific error occurrence.
Include this value when contacting support.
    Example: /traces/0123456789abcdef0123456789abcdef

  - `code` (string, required)
    Stable machine-readable error code for programmatic error handling. Unlike the HTTP `status` or free-form `detail`, this code is guaranteed not to change between versions for a given error condition, so it is safe to branch on in client code. Defaults to `unspecified` when the server has not assigned a specific code.
    Example: blockchain.not_found

## Response 400 examples:

  - `Invalid request` (unknown)

## Response 409 examples:

  - `Account is not ready to sign transactions` (unknown)

  - `Transaction state does not allow this operation` (unknown)

  - `Another send is in progress` (unknown)

  - `Transaction already accepted` (unknown)

## Response 429 examples:

  - `The transaction has reached its shared manual and automatic send-attempt limit` (unknown)

  - `The workspace has reached its signer and invitation limit` (unknown)

## Response default examples:

  - `Unexpected failure` (unknown)

