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
| Environment | URL |
|---|---|
| Production | https://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" }'| Field | Type | Required | Description |
|---|---|---|---|
protocol | string | Yes | cggmp21 (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"
}'| Field | Type | Required | Description |
|---|---|---|---|
walletId | string | Yes | Target wallet |
sessionId | string | Yes | An open signing session |
message | string | Yes | Message or transaction hash to sign |
encoding | string | No | hex (default) or base64 |
Response 200 OK
{
"signature": "0x1a2b3c...4d5e6f...1b",
"r": "0x1a2b3c4d5e6f...",
"s": "0x4d5e6f1a2b3c..."
}Signature format by protocol
| Protocol | Fields |
|---|---|
| CGGMP21 | r, s, and a recovery byte (ECDSA) |
| FROST | 64-byte Schnorr signature |
| BLS | compressed 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" }| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_protocol / invalid_encoding | Bad request input |
| 401 | unauthorized | Missing or invalid bearer token |
| 403 | forbidden | Token lacks the required role/permission |
| 404 | wallet_not_found | Unknown wallet |
| 409 | reshare_in_progress | A reshare is already running for this wallet |
| 503 | insufficient_signers | Fewer 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