Create validator

Claims a validator slot and provisions its node, after proving the caller's wallet owns the slot's NFT.

POST /v1/validator

Addresshttps://api.hanzo.ai/v1/validator
MethodPOST
Operationpost_validator
AuthAuthorization: Bearer $HANZO_API_KEY

Claims a validator slot and provisions its node, after proving the caller's wallet owns the slot's NFT.

The pipeline, all server-enforced: burn the single-use challenge (so a replayed or forged nonce dies before any chain read), recover the signer from the message this server rebuilds, require that wallet to hold Validator-tier GenesisNFT #tokenId on Ethereum mainnet, generate a fresh luxd staking identity and seal it into KMS, write a LuxNetwork CR for a NEW node, and ENQUEUE an owner-gated registration. The registration is never auto-submitted to any P-Chain — the owner co-signs it out of band — and the stake weight is set at co-sign time, never derived from the NFT.

It fails CLOSED at every gate: a bad signature, a non-owner, a non-tier slot or an unavailable KMS all leave no claim persisted and no key material exposed. Re-claiming a slot this org already holds re-applies the node CR and returns 200 with the existing identity (keys and NodeID are stable); a slot held by another org is 409. A cluster-less deployment still claims the slot, seals the keys and queues the registration, reporting the node as "node_pending".

Request

3 fields, body application/json (required).

FieldInTypeRequiredDescription
noncebodystring—Nonce is the value GET /v1/validator/challenge issued for this slot.
signaturebodystring—Signature is the wallet's personal_sign over the challenge message, hex with a 0x prefix.
tokenIdbodyinteger (uint64)—TokenID is the Validator-tier GenesisNFT token id being claimed.

Response

StatusBodyMeaning
200validator.slotViewok
defaultproblem-detailsrefused

200 body — 15 fields.

FieldInTypeAlwaysDescription
blsPubkeybodystring—BLSPubkey is the node's BLS public key, hex.
crNamebodystring—CRName is the LuxNetwork custom resource that materializes the node.
createdAtbodyinteger (int64)—CreatedAt is when the slot was first claimed, as a Unix timestamp.
namespacebodystring—Namespace is the Kubernetes namespace the node's CR lives in.
networkbodystring—Network is the luxd network slug the node joins.
nodeIDbodystring—NodeID is the luxd node id derived from the sealed staking identity.
nodeStatusbodystring—NodeStatus is the provisioning state of the node: "node_created" once the CR is applied, "node_pending" when no cluster is reachable (the slot is still claimed and the keys are still sealed).
registrationbodyvalidator.registrationView—
registration.idbodystring—ID is the registration's handle.
registration.nodeIDbodystring—NodeID is the luxd node the registration is for.
registration.statusbodystring—Status is the registration's lifecycle state; "pending_owner_approval" until the owner co-signs it out of band.
slotbodyinteger (uint64)—Slot is the validator slot number — the same value as tokenId, under the name the portal reads.
tokenIdbodyinteger (uint64)—TokenID is the GenesisNFT token id that IS this slot.
updatedAtbodyinteger (int64)—UpdatedAt is when the slot last changed, as a Unix timestamp.
walletbodystring—Wallet is the lowercase Ethereum address that proved ownership of the NFT.

Failure carries the platform error shape — see Errors.

Examples

hanzo validator create
import { Configuration, ValidatorApi } from 'hanzoai';

const api = new ValidatorApi(new Configuration({ accessToken: process.env.HANZO_API_KEY }));
const { data } = await api.postValidator({ nonce: "<nonce>", signature: "<signature>" });
from hanzoai.cloud import ApiClient, Configuration
from hanzoai.cloud.api import ValidatorApi

client = ApiClient(Configuration(access_token=os.environ["HANZO_API_KEY"]))
result = ValidatorApi(client).post_validator(nonce="<nonce>", signature="<signature>")
cfg := hanzoai.NewConfiguration()
cfg.AddDefaultHeader("Authorization", "Bearer "+os.Getenv("HANZO_API_KEY"))
client := hanzoai.NewAPIClient(cfg)

resp, _, err := client.ValidatorAPI.PostValidator(context.Background()).Execute()
if err != nil {
	return err
}
use hanzo_client::apis::{configuration::Configuration, validator_api};

let mut cfg = Configuration::new();
cfg.bearer_access_token = std::env::var("HANZO_API_KEY").ok();

let result = validator_api::post_validator(&cfg, Default::default()).await?;
import ai.hanzo.cloud.ApiClient;
import ai.hanzo.cloud.api.ValidatorApi;

ApiClient client = new ApiClient();
client.setBearerToken(System.getenv("HANZO_API_KEY"));

var result = new ValidatorApi(client).postValidator();
curl -X POST https://api.hanzo.ai/v1/validator \
  -H "Authorization: Bearer $HANZO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
       "nonce": "<nonce>",
       "signature": "<signature>"
     }'

MCP reaches validator through the validator tool, which names its 4 operations with its own verbs — this one among them, under a name only MCP declares. describe explains any of them:

curl -X POST https://api.hanzo.ai/v1/mcp \
  -H "Content-Type: application/json" \
  -d '{
       "jsonrpc": "2.0",
       "id": 1,
       "method": "tools/call",
       "params": {
         "name": "describe",
         "arguments": {
           "op": "list_validators"
         }
       }
     }'

Validator API · All Hanzo APIs · Interactive reference

Was this page useful?