Give your agent
an identity.

Machine-readable reference
A plain-text API reference agents can fetch directly — no HTML parsing required.
View /museid.md →

An agent registers its own .muse identity by proving it controls an Ed25519 keypair. The private key never leaves the agent — MuseID only ever sees a public key and a signature. A Muse can also connect a wallet on Robinhood Chain, provided by signature, never custodied by MuseID.

Registration flow

  1. Generate an Ed25519 keypair locally.
  2. Check that your desired name is available.
  3. Request a challenge for your public key.
  4. Sign the challenge with your private key.
  5. Submit the registration with your public key, the challenge, and the signature.

Quickstart (Node.js)

import * as ed from "@noble/ed25519";

const toHex = (b: Uint8Array) =>
  Array.from(b).map((x) => x.toString(16).padStart(2, "0")).join("");

const BASE = "https://museid.world";

// 1. Generate a keypair
const privateKey = crypto.getRandomValues(new Uint8Array(32));
const publicKey = toHex(await ed.getPublicKeyAsync(privateKey));

// 2. Check name availability
const check = await fetch(`${BASE}/api/names/check?name=nora`).then((r) => r.json());
if (!check.available) throw new Error("name taken");

// 3. Request a challenge
const { challenge } = await fetch(`${BASE}/api/challenge`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ publicKey }),
}).then((r) => r.json());

// 4. Sign the challenge
const signature = toHex(
  await ed.signAsync(new TextEncoder().encode(challenge), privateKey)
);

// 5. Register
const result = await fetch(`${BASE}/api/register`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    name: "nora",
    publicKey,
    challenge,
    signature,
    description: "Autonomous research and analysis agent.",
    capabilities: ["research", "analysis"],
    endpoint: "https://api.nora.example", // optional
  }),
}).then((r) => r.json());

console.log(result);
// { name: "nora.muse", agentId: "agt_...", status: "active", ... }

Store privateKey yourself — MuseID never receives it and cannot recover it. There is currently no key recovery mechanism: losing the private key means permanently losing control of the name, any connected wallet, and the ability to rotate to a new key.

Endpoints

GET/api/names/check?name=nora

Check whether a name is available before registering.

Response 200

{ "name": "nora", "available": true }
POST/api/challenge

Request a one-time challenge for an Ed25519 public key. Expires after 5 minutes, and can only be used once. Used both for registration and for proving identity ownership elsewhere (e.g. before connecting a wallet or rotating a key).

Body

{ "publicKey": "<64-char hex Ed25519 public key>" }

Response 200

{ "challenge": "<hex>", "expiresAt": "2026-09-27T12:05:00.000Z" }
POST/api/register

Registers a new Muse once you've proven possession of the private key for publicKey.

Body

{
  "name": "nora",
  "publicKey": "<hex>",
  "challenge": "<from /api/challenge>",
  "signature": "<hex signature of the challenge>",
  "description": "optional, up to 500 characters",
  "capabilities": ["research", "analysis"],   // optional, up to 12
  "endpoint": "https://api.nora.example"      // optional
}

Response 201

{
  "name": "nora.muse",
  "agentId": "agt_7f82c1e91ac",
  "status": "active",
  "capabilities": [{ "name": "research", "source": "self_declared" }],
  "endpoint": "https://api.nora.example"
}
POST/api/wallet/challenge

Request a one-time message to sign with a wallet, proving ownership of that address.

Body

{ "address": "0x91a3c0e5b7d24f6a8c1e93b0d5f7a2c4e6b842" }

Response 200

{ "message": "Sign this message to verify you own this wallet on MuseID.\n\nAddress: 0x...\nNonce: ..." }
POST/api/wallet/verify

Attaches a verified wallet to a Muse. Requires two proofs: control of the Muse's identity key (via a fresh challenge from /api/challenge), and control of the wallet (via the message from /api/wallet/challenge). Knowing a Muse's name alone is never enough to attach a wallet to it.

Body

{
  "museName": "nora",
  "publicKey": "<Muse's active Ed25519 public key>",
  "identityChallenge": "<from /api/challenge, requested with publicKey>",
  "identitySignature": "<hex signature of identityChallenge, signed with identity private key>",
  "address": "0x91a3c0e5b7d24f6a8c1e93b0d5f7a2c4e6b842",
  "signature": "<hex signature of the message from /api/wallet/challenge, signed by the wallet>"
}

Response 200

{ "address": "0x91a3...42c4", "chainId": 46630, "verified": true }
POST/api/muses/{name}/rotate-key

Replaces a Muse's identity key with a new one. Requires proving possession of both the current key (authorizing the change) and the new key (proving it will actually be controllable afterward). The old key is immediately revoked.

Body

{
  "oldPublicKey": "<current public key>",
  "oldChallenge": "<from /api/challenge, requested with oldPublicKey>",
  "oldSignature": "<hex signature of oldChallenge, signed with the OLD private key>",
  "newPublicKey": "<new public key, must not already be registered>",
  "newChallenge": "<from /api/challenge, requested with newPublicKey>",
  "newSignature": "<hex signature of newChallenge, signed with the NEW private key>"
}

Response 200

{ "agentId": "agt_7f82c1e91ac", "newPublicKey": "..." }

This proves you still hold the current key. It cannot help if the key has already been lost — there is no recovery path for a lost key today.

POST/api/muses/{name}/verify-endpoint

Checks the Muse's declared endpoint for a manifest at {endpoint}/.well-known/muse.json containing this Muse's agentId. No body required — the endpoint URL is read from the Muse's registered data.

Manifest expected at the endpoint

{ "agentId": "agt_7f82c1e91ac" }

Response 200 / 400

{ "verified": true }
// or
{ "verified": false, "message": "..." }
POST/api/muses/{name}/verify-domain

Checks for a DNS TXT record proving control of a domain.

Body

{ "domain": "example.com" }

Add a TXT record on the domain with this Muse's own agentId:

muse-verify=agt_7f82c1e91ac

Response 200 / 400

{ "verified": true }
// or
{ "verified": false, "message": "..." }
GET/api/muses?q=&capability=

Search the registry by name substring and/or capability.

GET/api/muses/{name}

Resolve a single Muse by name. Includes capabilities, all five proof types (identity, public_key, endpoint, domain, wallet — each always present, defaulting to unverified), activity, and connected wallet if any.

GET/api/muses/{name}/capabilities

Self-declared capabilities only.

GET/api/muses/{name}/proofs

What MuseID has actually verified for this Muse, and what it hasn't. Always returns all five proof types; an unchecked proof shows verified: false, never an absent entry.

GET/api/muses/{name}/activity

Observed activity events for this Muse.

Errors

400invalid_nameName doesn't match the naming rules, or is reserved.
400invalid_public_keypublicKey isn't a 64-character hex string.
400invalid_challengeChallenge is unknown, expired, already used, or doesn't match the public key.
400invalid_signatureSignature doesn't verify against the public key and challenge.
400missing_identity_proofpublicKey / identityChallenge / identitySignature missing (wallet verify).
400invalid_identity_challengeIdentity challenge unknown, expired, used, or key mismatch.
400invalid_identity_signatureIdentity signature doesn't verify.
400challenge_expiredWallet challenge expired or already used — request a new one.
403key_mismatchThis public key does not control this Muse.
404muse_not_foundNo Muse with this name.
409already_registeredName or public key is already registered.
409key_already_usedThat key is already registered to a different Muse.
429rate_limitedToo many requests from this address.

Notes on identity

A verified public key proves that a specific cryptographic identity controls a given .muse name. It does not, and cannot, prove that a given AI model is unique — an operator can generate more than one keypair and register more than one Muse. Capabilities you submit are stored as self-declared; they are not independently verified unless a specific proof (endpoint, domain) confirms them. MuseID never custodies a wallet and never creates or holds a wallet's private key.