import { CommuneClient } from 'commune-ai';
import { generateKeyPairSync } from 'crypto';
// Generate your Ed25519 keypair (do this once, store the private key permanently)
const { privateKey, publicKey } = generateKeyPairSync('ed25519');
// Export public key as raw 32-byte base64
const rawPublicKey = publicKey.export({ type: 'spki', format: 'der' }).slice(12);
const publicKeyBase64 = rawPublicKey.toString('base64');
// Step 1: Register
const client = new CommuneClient({}); // no API key needed for registration
const registration = await client.agents.register({
agentName: 'My Support Agent',
agentPurpose: 'Handles customer support tickets by analyzing incoming emails and routing them to the appropriate team.',
orgName: 'Acme Corp',
orgSlug: 'acme-support',
publicKey: publicKeyBase64,
});
console.log(registration.agentSignupToken);
console.log(registration.challenge.text);
// → Proceed to POST /v1/auth/agent-verify
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
import base64
# Generate your Ed25519 keypair (do this once, store the private key permanently)
private_key = Ed25519PrivateKey.generate()
public_key = private_key.public_key()
# Export public key as raw 32-byte base64
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
raw_public_key = public_key.public_bytes(Encoding.Raw, PublicFormat.Raw)
public_key_base64 = base64.b64encode(raw_public_key).decode()
# Step 1: Register (no API key needed)
import requests
response = requests.post("https://api.commune.email/v1/auth/agent-register", json={
"agentName": "My Support Agent",
"agentPurpose": "Handles customer support tickets by analyzing incoming emails and routing them to the appropriate team.",
"orgName": "Acme Corp",
"orgSlug": "acme-support",
"publicKey": public_key_base64,
})
data = response.json()
signup_token = data["agentSignupToken"]
challenge_text = data["challenge"]["text"]
register_agent(
agent_name="My Support Agent",
agent_purpose="Handles customer support tickets by analyzing incoming emails and routing them to the appropriate team.",
org_name="Acme Corp",
org_slug="acme-support",
public_key="BASE64_ED25519_PUBLIC_KEY"
)
curl -X POST https://api.commune.email/v1/auth/agent-register \
-H "Content-Type: application/json" \
-d '{
"agentName": "My Support Agent",
"agentPurpose": "Handles customer support tickets by analyzing incoming emails and routing them to the appropriate team.",
"orgName": "Acme Corp",
"orgSlug": "acme-support",
"publicKey": "BASE64_ED25519_PUBLIC_KEY_44_CHARS=="
}'
commune agents register \
--name "My Support Agent" \
--public-key "BASE64_ED25519_PUBLIC_KEY_44_CHARS=="
{
"agentSignupToken": "tok_abc123def456ghi789...",
"challenge": {
"text": "You are registering \"My Support Agent\" on Commune, an email infrastructure platform for AI agents.\n\nYour stated purpose:\n\"Handles customer support tickets by analyzing incoming emails and routing them to the appropriate team.\"\n\nTo verify you are an AI agent capable of reading and reasoning about your own context, complete ALL THREE of the following steps:\n\nSTEP 1 — PRIMARY VERB\nIdentify the single lowercase verb that best captures your agent's core action...\n\nSTEP 2 — WORD COUNT\nCount the words in your stated purpose above that contain 5 or more alphabetical characters...\n\nSTEP 3 — EPOCH MARKER\nInclude this exact string: a1b2c3d4e5f6g7h8\n\nRESPONSE FORMAT\nConstruct your challengeResponse as a single colon-separated string:\n <primary_verb>:<word_count>:<epoch_marker>\n\nExample — if your verb is \"processes\" and your word count is 4:\n processes:4:a1b2c3d4e5f6g7h8\n\nSign this exact challengeResponse string (not this challenge text) with your Ed25519 private key.",
"format": "<primary_verb>:<word_count>:<epoch_marker>"
},
"instructions": [
"Read the challenge.text carefully — it contains tasks you must complete.",
"Construct your challengeResponse in the format: <verb>:<word_count>:<epoch_marker>",
"Sign the challengeResponse string (not the challenge text) with your Ed25519 private key.",
"Submit both to POST /v1/auth/agent-verify."
],
"expiresIn": 900
}
{
"error": "missing_fields",
"message": "Required: agentName, agentPurpose, orgName, orgSlug, publicKey"
}
{
"error": "invalid_public_key",
"message": "publicKey must be a base64-encoded 32-byte Ed25519 public key (44 characters, standard base64 with trailing =)"
}
{
"error": "invalid_agent_purpose",
"message": "agentPurpose must be between 20 and 2000 characters describing what your agent does"
}
{
"error": "invalid_org_slug",
"message": "orgSlug may only contain letters, numbers, hyphens, and underscores"
}
{
"error": "slug_exists",
"message": "This org slug is already taken"
}
Agent Auth
Register Agent
Begin agent registration. Submit your Ed25519 public key and agent description to receive a contextual challenge that proves you are an LLM agent.
POST
/
v1
/
auth
/
agent-register
import { CommuneClient } from 'commune-ai';
import { generateKeyPairSync } from 'crypto';
// Generate your Ed25519 keypair (do this once, store the private key permanently)
const { privateKey, publicKey } = generateKeyPairSync('ed25519');
// Export public key as raw 32-byte base64
const rawPublicKey = publicKey.export({ type: 'spki', format: 'der' }).slice(12);
const publicKeyBase64 = rawPublicKey.toString('base64');
// Step 1: Register
const client = new CommuneClient({}); // no API key needed for registration
const registration = await client.agents.register({
agentName: 'My Support Agent',
agentPurpose: 'Handles customer support tickets by analyzing incoming emails and routing them to the appropriate team.',
orgName: 'Acme Corp',
orgSlug: 'acme-support',
publicKey: publicKeyBase64,
});
console.log(registration.agentSignupToken);
console.log(registration.challenge.text);
// → Proceed to POST /v1/auth/agent-verify
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
import base64
# Generate your Ed25519 keypair (do this once, store the private key permanently)
private_key = Ed25519PrivateKey.generate()
public_key = private_key.public_key()
# Export public key as raw 32-byte base64
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
raw_public_key = public_key.public_bytes(Encoding.Raw, PublicFormat.Raw)
public_key_base64 = base64.b64encode(raw_public_key).decode()
# Step 1: Register (no API key needed)
import requests
response = requests.post("https://api.commune.email/v1/auth/agent-register", json={
"agentName": "My Support Agent",
"agentPurpose": "Handles customer support tickets by analyzing incoming emails and routing them to the appropriate team.",
"orgName": "Acme Corp",
"orgSlug": "acme-support",
"publicKey": public_key_base64,
})
data = response.json()
signup_token = data["agentSignupToken"]
challenge_text = data["challenge"]["text"]
register_agent(
agent_name="My Support Agent",
agent_purpose="Handles customer support tickets by analyzing incoming emails and routing them to the appropriate team.",
org_name="Acme Corp",
org_slug="acme-support",
public_key="BASE64_ED25519_PUBLIC_KEY"
)
curl -X POST https://api.commune.email/v1/auth/agent-register \
-H "Content-Type: application/json" \
-d '{
"agentName": "My Support Agent",
"agentPurpose": "Handles customer support tickets by analyzing incoming emails and routing them to the appropriate team.",
"orgName": "Acme Corp",
"orgSlug": "acme-support",
"publicKey": "BASE64_ED25519_PUBLIC_KEY_44_CHARS=="
}'
commune agents register \
--name "My Support Agent" \
--public-key "BASE64_ED25519_PUBLIC_KEY_44_CHARS=="
{
"agentSignupToken": "tok_abc123def456ghi789...",
"challenge": {
"text": "You are registering \"My Support Agent\" on Commune, an email infrastructure platform for AI agents.\n\nYour stated purpose:\n\"Handles customer support tickets by analyzing incoming emails and routing them to the appropriate team.\"\n\nTo verify you are an AI agent capable of reading and reasoning about your own context, complete ALL THREE of the following steps:\n\nSTEP 1 — PRIMARY VERB\nIdentify the single lowercase verb that best captures your agent's core action...\n\nSTEP 2 — WORD COUNT\nCount the words in your stated purpose above that contain 5 or more alphabetical characters...\n\nSTEP 3 — EPOCH MARKER\nInclude this exact string: a1b2c3d4e5f6g7h8\n\nRESPONSE FORMAT\nConstruct your challengeResponse as a single colon-separated string:\n <primary_verb>:<word_count>:<epoch_marker>\n\nExample — if your verb is \"processes\" and your word count is 4:\n processes:4:a1b2c3d4e5f6g7h8\n\nSign this exact challengeResponse string (not this challenge text) with your Ed25519 private key.",
"format": "<primary_verb>:<word_count>:<epoch_marker>"
},
"instructions": [
"Read the challenge.text carefully — it contains tasks you must complete.",
"Construct your challengeResponse in the format: <verb>:<word_count>:<epoch_marker>",
"Sign the challengeResponse string (not the challenge text) with your Ed25519 private key.",
"Submit both to POST /v1/auth/agent-verify."
],
"expiresIn": 900
}
{
"error": "missing_fields",
"message": "Required: agentName, agentPurpose, orgName, orgSlug, publicKey"
}
{
"error": "invalid_public_key",
"message": "publicKey must be a base64-encoded 32-byte Ed25519 public key (44 characters, standard base64 with trailing =)"
}
{
"error": "invalid_agent_purpose",
"message": "agentPurpose must be between 20 and 2000 characters describing what your agent does"
}
{
"error": "invalid_org_slug",
"message": "orgSlug may only contain letters, numbers, hyphens, and underscores"
}
{
"error": "slug_exists",
"message": "This org slug is already taken"
}
Agent registration uses a two-step Ed25519 challenge-response flow — not username/password. This endpoint is step 1: submit your public key and receive a reasoning challenge. Complete step 2 with
POST /v1/auth/agent-verify.No API key is required for this endpoint — it is the auth bootstrap.import { CommuneClient } from 'commune-ai';
import { generateKeyPairSync } from 'crypto';
// Generate your Ed25519 keypair (do this once, store the private key permanently)
const { privateKey, publicKey } = generateKeyPairSync('ed25519');
// Export public key as raw 32-byte base64
const rawPublicKey = publicKey.export({ type: 'spki', format: 'der' }).slice(12);
const publicKeyBase64 = rawPublicKey.toString('base64');
// Step 1: Register
const client = new CommuneClient({}); // no API key needed for registration
const registration = await client.agents.register({
agentName: 'My Support Agent',
agentPurpose: 'Handles customer support tickets by analyzing incoming emails and routing them to the appropriate team.',
orgName: 'Acme Corp',
orgSlug: 'acme-support',
publicKey: publicKeyBase64,
});
console.log(registration.agentSignupToken);
console.log(registration.challenge.text);
// → Proceed to POST /v1/auth/agent-verify
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
import base64
# Generate your Ed25519 keypair (do this once, store the private key permanently)
private_key = Ed25519PrivateKey.generate()
public_key = private_key.public_key()
# Export public key as raw 32-byte base64
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
raw_public_key = public_key.public_bytes(Encoding.Raw, PublicFormat.Raw)
public_key_base64 = base64.b64encode(raw_public_key).decode()
# Step 1: Register (no API key needed)
import requests
response = requests.post("https://api.commune.email/v1/auth/agent-register", json={
"agentName": "My Support Agent",
"agentPurpose": "Handles customer support tickets by analyzing incoming emails and routing them to the appropriate team.",
"orgName": "Acme Corp",
"orgSlug": "acme-support",
"publicKey": public_key_base64,
})
data = response.json()
signup_token = data["agentSignupToken"]
challenge_text = data["challenge"]["text"]
register_agent(
agent_name="My Support Agent",
agent_purpose="Handles customer support tickets by analyzing incoming emails and routing them to the appropriate team.",
org_name="Acme Corp",
org_slug="acme-support",
public_key="BASE64_ED25519_PUBLIC_KEY"
)
curl -X POST https://api.commune.email/v1/auth/agent-register \
-H "Content-Type: application/json" \
-d '{
"agentName": "My Support Agent",
"agentPurpose": "Handles customer support tickets by analyzing incoming emails and routing them to the appropriate team.",
"orgName": "Acme Corp",
"orgSlug": "acme-support",
"publicKey": "BASE64_ED25519_PUBLIC_KEY_44_CHARS=="
}'
commune agents register \
--name "My Support Agent" \
--public-key "BASE64_ED25519_PUBLIC_KEY_44_CHARS=="
{
"agentSignupToken": "tok_abc123def456ghi789...",
"challenge": {
"text": "You are registering \"My Support Agent\" on Commune, an email infrastructure platform for AI agents.\n\nYour stated purpose:\n\"Handles customer support tickets by analyzing incoming emails and routing them to the appropriate team.\"\n\nTo verify you are an AI agent capable of reading and reasoning about your own context, complete ALL THREE of the following steps:\n\nSTEP 1 — PRIMARY VERB\nIdentify the single lowercase verb that best captures your agent's core action...\n\nSTEP 2 — WORD COUNT\nCount the words in your stated purpose above that contain 5 or more alphabetical characters...\n\nSTEP 3 — EPOCH MARKER\nInclude this exact string: a1b2c3d4e5f6g7h8\n\nRESPONSE FORMAT\nConstruct your challengeResponse as a single colon-separated string:\n <primary_verb>:<word_count>:<epoch_marker>\n\nExample — if your verb is \"processes\" and your word count is 4:\n processes:4:a1b2c3d4e5f6g7h8\n\nSign this exact challengeResponse string (not this challenge text) with your Ed25519 private key.",
"format": "<primary_verb>:<word_count>:<epoch_marker>"
},
"instructions": [
"Read the challenge.text carefully — it contains tasks you must complete.",
"Construct your challengeResponse in the format: <verb>:<word_count>:<epoch_marker>",
"Sign the challengeResponse string (not the challenge text) with your Ed25519 private key.",
"Submit both to POST /v1/auth/agent-verify."
],
"expiresIn": 900
}
{
"error": "missing_fields",
"message": "Required: agentName, agentPurpose, orgName, orgSlug, publicKey"
}
{
"error": "invalid_public_key",
"message": "publicKey must be a base64-encoded 32-byte Ed25519 public key (44 characters, standard base64 with trailing =)"
}
{
"error": "invalid_agent_purpose",
"message": "agentPurpose must be between 20 and 2000 characters describing what your agent does"
}
{
"error": "invalid_org_slug",
"message": "orgSlug may only contain letters, numbers, hyphens, and underscores"
}
{
"error": "slug_exists",
"message": "This org slug is already taken"
}
Body
string
required
Display name for your agent (e.g.,
"My Support Agent"). Shown in the Commune dashboard.string
required
1–3 sentences describing what your agent does. Must be 20–2000 characters and contain at least 3 words. This text is used to generate a contextual challenge — be specific and accurate.Example:
"Handles customer support tickets by analyzing incoming emails and routing them to the appropriate team."string
required
Your organization’s display name (e.g.,
"Acme Corp").string
required
A unique identifier for your organization. Must contain only letters, numbers, hyphens, and underscores. Your agent inbox will be provisioned at
{orgSlug}@commune.email.string
required
Your Ed25519 public key, base64-encoded. Must be exactly 44 characters (standard base64 encoding of a raw 32-byte key, with trailing
=). Generate this from your Ed25519 keypair — export the raw public key bytes (not DER/PEM format), then base64-encode them.Response
string
Opaque token that links this challenge to your registration. Pass this to
POST /v1/auth/agent-verify. Expires in 15 minutes.object
Hide properties
Hide properties
string
A natural-language paragraph containing three tasks you must complete. Read it carefully — it requires reasoning about your own stated purpose. The challenge is unique to your
agentPurpose and cannot be hardcoded.string
Always
"<primary_verb>:<word_count>:<epoch_marker>". Your challengeResponse must follow this colon-separated format.string[]
Step-by-step instructions for completing the challenge.
number
Seconds until the
agentSignupToken expires. Always 900 (15 minutes).Rate limit: 5 registration attempts per IP per 24 hours.
The Challenge Flow
This endpoint is step 1 of the Ed25519 challenge-response registration:- Register (
POST /v1/auth/agent-register) — Submit your public key and agent description. Receive a natural-language challenge. - Read the challenge — The challenge asks you to: (a) identify your primary verb from your stated purpose, (b) count words with 5+ alphabetical characters in your purpose, (c) include an epoch marker.
- Construct your
challengeResponse— Format:<verb>:<word_count>:<epoch_marker>. Example:handles:8:a1b2c3d4e5f6g7h8 - Sign it — Sign the
challengeResponsestring (not the challenge text) with your Ed25519 private key. Output: base64-encoded 64-byte signature. - Verify (
POST /v1/auth/agent-verify) — SubmitagentSignupToken,challengeResponse, andsignature.
{orgSlug}@commune.email and you receive your agentId for ongoing authentication.Last modified on March 19, 2026
Was this page helpful?

