Wallets
Package wallets is blockchain key custody: create wallets, rotate their keys, and sign with them.
Package wallets is blockchain key custody: create wallets, rotate their keys, and sign with them.
| Base URL | https://api.hanzo.ai |
| Operations | 8 |
| Auth | Authorization: Bearer $HANZO_API_KEY |
wallets
Rolls one wallet's signing material through its own custody backend and answers the wallet with whatever address that produced.
POST /v1/wallets/{id}/keys
Rolls one wallet's signing material through its own custody backend and answers the wallet with whatever address that produced. For KMS custody a fresh secp256k1 key is generated and sealed, which CHANGES the address — funds and approvals at the old address do not move. For a Safe the address is counterfactual and the owner shares are ring-managed, so rotation is a no-op and the address is unchanged. A backend that is not configured fails closed with 503 rather than leaving the wallet half-rotated.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes |
Composes a Safe transaction on the MPC ring and answers its EIP-712 hash together with the owner approval the ring's threshold signature produced.
POST /v1/wallets/{id}/safe-tx
Composes a Safe transaction on the MPC ring and answers its EIP-712 hash together with the owner approval the ring's threshold signature produced. Only a wallet whose custody is "safe" can do this — any other custody is a 400, because the backend itself is asked whether it can propose rather than the kind being switched on. The ring computes the Safe-tx hash bound to the Safe contract and the chain id, so the hash a caller gets back is the one the Safe will verify. This PROPOSES: it does not execute the transaction.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes |
Request body — application/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
chainId | integer | — | ChainID is the EVM chain the Safe transaction is bound to. |
data | string | — | Data is the call data, hex-encoded. |
nonce | integer | — | Nonce is the Safe's transaction nonce. |
to | string | — | To is the transaction's target address. |
value | string | — | Value is the native-token amount to send, as a decimal string in wei. |
Produces a secp256k1 signature from one of the caller org's wallets over a 32-byte digest, through whichever custody backend that wallet uses.
POST /v1/wallets/{id}/sign
Produces a secp256k1 signature from one of the caller org's wallets over
a 32-byte digest, through whichever custody backend that wallet uses. Give it
either a digest (32 bytes as hex, signed verbatim) or a message (hashed
with Keccak256 first) — exactly one is required. The private key never leaves
its backend: KMS custody opens the sealed key in-process, MPC custody produces
a threshold signature on the ring. The answer carries the digest that was
signed alongside the signature, so a caller can verify what it got.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes |
Request body — application/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
digest | string | — | Digest is a pre-computed 32-byte digest as hex, with or without the 0x prefix. |
message | string | — | Message is arbitrary text to hash with Keccak256 and sign. |
Returns one of the caller org's wallets: its scope, custody kind, tier, chain and on-chain address.
GET /v1/wallets/{id}
Returns one of the caller org's wallets: its scope, custody kind, tier, chain and on-chain address. The custody handle to the signing material is never part of the answer. A wallet id another org owns reads as not found, so the response cannot confirm that it exists.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
id | path | string | yes |
Returns the caller org's wallet accounts, newest first.
GET /v1/wallets/accounts
Returns the caller org's wallet accounts, newest first. Accounts are physically org-scoped, so another tenant's are not reachable from here.
Opens a named wallet account for the caller's org.
POST /v1/wallets/accounts
Opens a named wallet account for the caller's org. An account is a GROUPING of wallets, not a key or a balance: wallets are created under one and can be listed by it. The org is stamped by the server from the validated principal, so a request can never open an account in another tenant.
Request body — application/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
name | string | — | Name is the account's label. |
Returns the caller org's wallets, newest first, optionally NARROWED within the org by project, agent or account.
GET /v1/wallets
Returns the caller org's wallets, newest first, optionally NARROWED within the org by project, agent or account. The org is always the bound isolation boundary — the filters only ever narrow inside it, so a caller can never widen past its own org.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
project | query | string | — | Project narrows to wallets scoped to one project. |
agent | query | string | — | Agent narrows to wallets scoped to one agent. |
account | query | string | — | Account narrows to wallets under one account id. |
Provisions a new signing identity under one of the caller org's accounts and answers the stored wallet including its on-chain address.
POST /v1/wallets
Provisions a new signing identity under one of the caller org's accounts and answers the stored wallet including its on-chain address. The custody backend generates the key material — a KMS-sealed secp256k1 key, an MPC threshold key on the ring, or a Safe smart wallet owned by one — and the HANDLE to it is kept server-side and never returned. A custody kind the deployment has not wired fails CLOSED with 503: a signature is never fabricated. The wallet is scoped to the org, the caller's ambient project, and optionally an agent and the named account; those narrowings are what its key ref is derived from, so each must be a url-safe segment.
Request body — application/json (required)
| Field | Type | Required | Description |
|---|---|---|---|
accountId | string | — | AccountID is the account this wallet belongs to. |
agent | string | — | Agent optionally narrows the wallet to one agent within the org. |
chain | string | — | Chain is the EVM chain this wallet is for, as "eip155:<n>" or a bare decimal chain id. |
custody | string | — | Custody selects the signing backend: "kms" (in-process, always available), "mpc" or "treasury" (the deployed MPC ring), |
name | string | — | Name is the wallet's display label. |
tier | string | — | Tier is the MPC wallet tier: hot, warm, cold, gas, bridge, contract_admin, validator, quarantine or disaster_recovery. |
How is this guide?