Hanzo

API Reference

REST API reference for the Hanzo MPC custody service

API Reference

The Hanzo MPC custody API is served at https://mpc.hanzo.ai under the /v1 prefix. Signing is session-based: create a wallet, open a session, then sign.

Authentication

Every request (except health) carries a bearer token issued by Hanzo IAM:

Authorization: Bearer <iam-access-token>

A service holding an external OIDC token can exchange it for an MPC token (the issuer must be allow-listed):

curl -X POST https://mpc.hanzo.ai/v1/auth/oidc \
  -H "Content-Type: application/json" \
  -d '{ "token": "<external-oidc-access-token>" }'

Machine callers may instead present a long-lived API key via X-API-Key. Roles (owner, admin, signer, viewer) and per-route permissions (e.g. mpc:sign) gate access.

Base URL

EnvironmentURL
Productionhttps://mpc.hanzo.ai

POST /v1/mpc/wallets

Create a wallet via distributed key generation (DKG) across the configured parties.

Request

curl -X POST https://mpc.hanzo.ai/v1/mpc/wallets \
  -H "Authorization: Bearer $IAM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "protocol": "cggmp21" }'
FieldTypeRequiredDescription
protocolstringYescggmp21 (ECDSA) or frost (Schnorr)

For a wallet in a specific vault with an explicit key type, use POST /v1/vaults/{vaultId}/wallets with { "name", "key_type", "protocol" }, where protocol is cggmp21, frost, lss, or sr25519.

Response 201 Created

{
  "walletId": "w_3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "address": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
  "protocol": "cggmp21",
  "threshold": "2-of-3",
  "isDefault": true,
  "status": "active",
  "createdAt": "2026-06-26T10:30:00Z"
}

GET /v1/wallets/{id}/addresses

Return the chain addresses derived from a wallet's public key.

curl https://mpc.hanzo.ai/v1/wallets/$WALLET_ID/addresses \
  -H "Authorization: Bearer $IAM_ACCESS_TOKEN"
{
  "ethereum": "0x742d35Cc6634C0532925a3b844Bc9e7595f2bD18",
  "bitcoin": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh",
  "solana": "7nYBzS3Yz5mY8Qm4iXqz1bWmHnf8QpHq3xWv6Yc9aBcD",
  "xrp": "rPdvC6ccq8hCdPKSPJkPmyZ4Mi1oG2FFkT",
  "ton": "EQByY8B0iZ0a..."
}

POST /v1/mpc/wallets/{id}/sessions

Open a signing session. A session scopes and authorizes the signatures that follow, and is consumed atomically — which makes every signature an explicit, auditable action.

curl -X POST https://mpc.hanzo.ai/v1/mpc/wallets/$WALLET_ID/sessions \
  -H "Authorization: Bearer $IAM_ACCESS_TOKEN"
{ "sessionId": "s_a1b2c3d4", "walletId": "w_3fa85f64-...", "expiresAt": "2026-06-26T10:45:00Z" }

List or revoke sessions with GET /v1/mpc/wallets/{id}/sessions and DELETE /v1/mpc/wallets/{id}/sessions/{sessionId}.


POST /v1/mpc/sign

Threshold-sign a message hash. The coordinator selects t available nodes and runs the signing protocol. Requires an open sessionId.

Request

curl -X POST https://mpc.hanzo.ai/v1/mpc/sign \
  -H "Authorization: Bearer $IAM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "walletId": "w_3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "sessionId": "s_a1b2c3d4",
    "message": "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
    "encoding": "hex"
  }'
FieldTypeRequiredDescription
walletIdstringYesTarget wallet
sessionIdstringYesAn open signing session
messagestringYesMessage or transaction hash to sign
encodingstringNohex (default) or base64

Response 200 OK

{
  "signature": "0x1a2b3c...4d5e6f...1b",
  "r": "0x1a2b3c4d5e6f...",
  "s": "0x4d5e6f1a2b3c..."
}

Signature format by protocol

ProtocolFields
CGGMP21r, s, and a recovery byte (ECDSA)
FROST64-byte Schnorr signature
BLScompressed G1 point signature

For settlement workflows with an explicit reason and policy check, use POST /v1/mpc/settlement/sign with { "walletId", "sessionId", "payload", "reason" }.


POST /v1/wallets/{id}/reshare

Proactive share refresh. Generates new shares for the same key, optionally changing the participant set or threshold. The public key and every derived address are unchanged.

curl -X POST https://mpc.hanzo.ai/v1/wallets/$WALLET_ID/reshare \
  -H "Authorization: Bearer $IAM_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "new_threshold": 3, "new_participants": ["node-0","node-1","node-2","node-3","node-4"] }'
{ "walletId": "w_3fa85f64-...", "newThreshold": 3, "keyType": "secp256k1", "status": "completed" }

GET /v1/status · GET /v1/info

Cluster status and capabilities.

curl https://mpc.hanzo.ai/v1/status -H "Authorization: Bearer $IAM_ACCESS_TOKEN"
{ "status": "healthy", "nodes": { "total": 5, "healthy": 5 }, "threshold": "3-of-5", "transport": "nats" }

GET /healthz

Liveness probe, no authentication.

curl https://mpc.hanzo.ai/healthz
{ "status": "ok", "node_id": "node-0", "connected_peers": 4, "threshold": 3 }

Error format

{ "error": "insufficient_signers", "message": "Fewer than t nodes are available", "request_id": "req_abc123" }
StatusCodeMeaning
400invalid_protocol / invalid_encodingBad request input
401unauthorizedMissing or invalid bearer token
403forbiddenToken lacks the required role/permission
404wallet_not_foundUnknown wallet
409reshare_in_progressA reshare is already running for this wallet
503insufficient_signersFewer than t nodes available

When a signer deviates, signing aborts with an identifiable-abort error that names the offending party and includes a signed blame proof.

How is this guide?

Last updated on

On this page