Skip to content

Create a vault

POST
/vaults

Create a vault — a key that is generated and held across multiple parties so that no single party (including XKOVA) can sign alone. The tier and controls are fixed at creation. Key generation runs asynchronously: the vault is returned in creating and becomes active shortly after (poll GET /vaults/{vaultId} or listen for the webhook).

object
tier
required

Where the vault’s keys live and who must authorize a signature. hosted — XKOVA-operated, gated by your end users’ tokens (embedded wallets). self — you hold a required share; XKOVA cannot sign without you. customer_tee — keys run in your own trusted execution environment.

string
Allowed values: hosted customer_tee self
name
required
string
<= 128 characters
policy_id

Optional policy to attach (configured with XKOVA)

string
end_user_sub

Hosted tier: bind the vault to one end-user subject

string
Example
{
"tier": "self",
"name": "treasury"
}

Vault accepted; key generation in progress.

object
id
required
string
tier
required

Where the vault’s keys live and who must authorize a signature. hosted — XKOVA-operated, gated by your end users’ tokens (embedded wallets). self — you hold a required share; XKOVA cannot sign without you. customer_tee — keys run in your own trusted execution environment.

string
Allowed values: hosted customer_tee self
name
required
string
status
required

creatingactive; resharing during a rotation (reshare_pending if one needs attention); frozen if halted

string
Allowed values: creating active resharing reshare_pending frozen
share_epoch

Increments each time the vault’s shares are rotated; the public key is unchanged

integer
public_keys
object
secp256k1

Compressed public key, hex

string
end_user_sub
string
created_at
required
string format: date-time

The request body or parameters failed validation.

Failures return a single human-readable error message; the HTTP status carries the category (400 validation, 401 auth, 403 refused, 404 missing, 409 conflict, 429 rate limit). When a signing request is refused for a specific reason, the message names it — for example the amount exceeds a spend limit, the policy denied the recipient, or the intent signature did not verify.

object
error
required
string
code
required

Stable machine slug (invalid_request, unauthorized, forbidden, not_found, conflict, rate_limited); a refused sign names the reason in the message

string
Example
{
"error": "amount must be a base-10 integer",
"code": "invalid_request"
}

Missing, malformed, or invalid request signature.

Failures return a single human-readable error message; the HTTP status carries the category (400 validation, 401 auth, 403 refused, 404 missing, 409 conflict, 429 rate limit). When a signing request is refused for a specific reason, the message names it — for example the amount exceeds a spend limit, the policy denied the recipient, or the intent signature did not verify.

object
error
required
string
code
required

Stable machine slug (invalid_request, unauthorized, forbidden, not_found, conflict, rate_limited); a refused sign names the reason in the message

string
Example
{
"error": "request signature did not verify",
"code": "unauthorized"
}

A quota or rate limit was reached. Retry later.

Failures return a single human-readable error message; the HTTP status carries the category (400 validation, 401 auth, 403 refused, 404 missing, 409 conflict, 429 rate limit). When a signing request is refused for a specific reason, the message names it — for example the amount exceeds a spend limit, the policy denied the recipient, or the intent signature did not verify.

object
error
required
string
code
required

Stable machine slug (invalid_request, unauthorized, forbidden, not_found, conflict, rate_limited); a refused sign names the reason in the message

string
Example
{
"error": "vault quota reached for this org",
"code": "rate_limited"
}