Skip to content

Core concepts

Five ideas cover the whole API.

You authenticate every request by signing it with an Ed25519 key. You generate the keypair, register the public half with XKOVA, and keep the private seed. XKOVA stores only public keys — it can verify your requests but can never impersonate you. See Authentication.

A vault is a key managed by MPC — generated and held as shares so no single party can sign alone. A vault has:

  • a tier (hosted / self / customer_tee) — fixed at creation, deciding who must authorize a signature (see How it works);
  • a statuscreatingactive, resharing during a key rotation, frozen if halted;
  • a stable public key — unchanged by rotations, so addresses never move.

Key generation runs asynchronously: a new vault returns creating and becomes active shortly after.

A wallet is a chain address derived under a vault. One vault can hold many wallets across chains (avalanche_c, base, bitcoin); they all share the vault’s underlying key and its controls. Deriving a wallet is instant.

An intent is the canonical, byte-exact description of a transaction — chain, vault, path, recipient, amount, asset, idempotency key. You sign the intent with your API key and send that signature; XKOVA binds it to exactly the transaction it will broadcast, so the recipient and amount cannot be altered after you approve. The SDK builds and signs intents for you.

  • On EVM you may send convenience fields (to, amount, asset) and the API forms the intent, or send the exact intent bytes yourself.
  • On Bitcoin you always send the signed intent bytes (the idempotency key is carried inside it).

Submitting a transaction is asynchronous — it returns 202 and then moves through these states:

StateMeaning
createdaccepted, queued for checks
policy_checkedpassed policy + limits
awaiting_cosignerMPC signing in progress
signedsignature produced
broadcastaccepted by the network’s validity checks and sent
confirmed / finalon-chain
failedbroadcast or chain error
rejectedblocked by policy, limits, or a bad intent

Track a transaction by polling GET /transactions/{txId} or, better, with webhooks.

A vault enforces controls before any signature: a recipient/asset policy, per-transaction and per-day spend limits, and — for hosted vaults — an end-user token per signature. A blocked transaction ends rejected with a reason; no partial signature is ever produced.

Every money-moving request carries an idempotency key you choose. Retrying with the same key returns the same transaction rather than sending twice — so a network hiccup or a retry never double-spends. Reusing a key with different content is an error.