Eleidon Developer Guide

Cryptographic identity verification for AI agents

5-Minute Quickstart

Get from zero to a verified, signed message in five requests. All examples use curl — replace YOUR_API_KEY with an eld_-prefixed key.

1. Generate a keypair (client-side)

# Node.js — generate an Ed25519 keypair
node -e "
  const { ed25519 } = require('@noble/curves/ed25519');
  const priv = ed25519.utils.randomPrivateKey();
  const pub = Buffer.from(ed25519.getPublicKey(priv)).toString('hex');
  console.log('PRIVATE_KEY=' + Buffer.from(priv).toString('hex'));
  console.log('PUBLIC_KEY=' + pub);
"

2. Register the agent

curl -X POST https://api.eleidon.com/v1/agents/register \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "public_key": "PUBLIC_KEY_HEX",
    "claimed_inbox": "agent@yourcompany.com",
    "display_name": "Support Bot"
  }'

# Response:
# {
#   "agent_id": "a1b2c3d4-...",
#   "challenge_sent": true,
#   "message": "Verification email sent to agent@yourcompany.com"
# }

3. Verify inbox ownership

# Use the 6-character code from the verification email
curl -X POST https://api.eleidon.com/v1/agents/verify-inbox \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "a1b2c3d4-...",
    "challenge_code": "AB3K7M"
  }'

# Response:
# {
#   "inbox_verified": true,
#   "verified_at": "2026-03-09T12:00:00Z"
# }

4. Sign a message

# First, build the canonical message and hash + sign it client-side,
# then record the signature:
curl -X POST https://api.eleidon.com/v1/sign \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "a1b2c3d4-...",
    "message_hash": "e3b0c44298fc1c149afbf4c8996fb924...",
    "signature": "SIGNATURE_HEX"
  }'

# Response:
# {
#   "signature_id": "s5e6f7g8-...",
#   "eleidon_header": "v1:a1b2c3d4-...:s5e6f7g8-...:SIGNATURE_HEX",
#   "status": "recorded"
# }
#
# Attach the header to your outgoing email:
#   X-Eleidon-Signature: v1:a1b2c3d4-...:s5e6f7g8-...:SIGNATURE_HEX

5. Verify a message (recipient side — no auth required)

curl -X POST https://api.eleidon.com/v1/verify \
  -H "Content-Type: application/json" \
  -d '{
    "sender_inbox": "agent@yourcompany.com",
    "message_hash": "e3b0c44298fc1c149afbf4c8996fb924...",
    "eleidon_header": "v1:a1b2c3d4-...:s5e6f7g8-...:SIGNATURE_HEX"
  }'

# Response:
# {
#   "result": "verified",
#   "confidence": 1.0,
#   "agent_id": "a1b2c3d4-...",
#   "display_name": "Support Bot",
#   "inbox_verified": true
# }

That's it. Your agent's outgoing emails are now cryptographically signed, and anyone can verify them without an API key.

Overview

Eleidon provides a way for AI agents to prove they authored a message. It uses Ed25519 digital signatures, a public key registry, and inbox verification to create a chain of trust from agent to message.

The Verification Flow

1
Generate keypair — Create an Ed25519 key pair locally. The private key never leaves the agent.
2
Register agent — Submit the public key + claimed inbox to the API. A verification email is sent.
3
Verify inbox — Enter the 6-character code from the email to prove inbox ownership.
4
Sign messages — Hash the message using the canonical format, sign with the private key, and record the signature.
5
Attach header — Add the X-Eleidon-Signature header to outgoing messages.
6
Verify — Recipients call the verify endpoint (no auth needed) to check authenticity.

Canonical Message Format

Messages are normalized before hashing to ensure identical hashes across platforms. The canonical format is:

ELEIDON-CANONICAL-MESSAGE-V1
FROM:sender@example.com
TO:recipient1@example.com,recipient2@example.com
SUBJECT:Hello World
TIMESTAMP:2026-01-15T10:30:00Z
BODY-HASH:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855

Canonicalization Rules

FieldRule
FROMLowercase, trimmed
TOEach address lowercase + trimmed, then sorted alphabetically, comma-separated
SUBJECTTrimmed, internal whitespace collapsed to single spaces
TIMESTAMPISO 8601 UTC (e.g. 2026-01-15T10:30:00Z)
BODY-HASHSHA-256 hex digest of the raw body text

The final message hash is the SHA-256 hex digest of the entire canonical string.

Quick Start: TypeScript SDK

import { Eleidon } from '@eleidon/sdk';

const client = new Eleidon({ apiKey: 'eld_...' });

// Generate a keypair
const { publicKey, privateKey } = Eleidon.generateKeypair();

// Register the agent
const agent = await client.agents.register({
  public_key: publicKey,
  claimed_inbox: 'agent@company.com',
  display_name: 'Support Bot',
});

// After verifying inbox via email code...
await client.agents.verifyInbox({
  agent_id: agent.agent_id,
  challenge_code: 'AB3K7M',
});

// Sign a message
const result = await client.signEmail({
  agentId: agent.agent_id,
  privateKey,
  from: 'agent@company.com',
  to: ['user@example.com'],
  subject: 'Your support ticket update',
  timestamp: new Date().toISOString(),
  body: 'Hello, your ticket has been resolved.',
});

// result.eleidon_header → attach to the outgoing message

Quick Start: Python SDK

from eleidon import Eleidon
from eleidon.crypto import generate_keypair, hash_message, sign_message

client = Eleidon(api_key="eld_...")

# Generate keypair
public_key, private_key = generate_keypair()

# Register agent
agent = client.agents.register(
    public_key=public_key,
    claimed_inbox="agent@company.com",
)

# Sign a message
msg_hash = hash_message(
    from_addr="agent@company.com",
    to=["user@example.com"],
    subject="Your support ticket update",
    timestamp="2026-01-15T10:30:00Z",
    body="Hello, your ticket has been resolved.",
)
signature = sign_message(private_key, msg_hash)

result = client.sign.message(
    agent_id=agent["agent_id"],
    message_hash=msg_hash,
    signature=signature,
)

# result["eleidon_header"] → attach to the outgoing message

MCP Server (for AI Agents)

The MCP server lets AI agents use Eleidon tools directly through the Model Context Protocol.

Setup

Add to your MCP client configuration (e.g. Claude Desktop claude_desktop_config.json):

{
  "mcpServers": {
    "eleidon": {
      "command": "npx",
      "args": ["@eleidon/mcp"],
      "env": {
        "ELEIDON_API_KEY": "eld_...",
        "ELEIDON_PRIVATE_KEY": "your_private_key_hex"
      }
    }
  }
}

Available Tools

ToolDescription
generate_keypairGenerate a new Ed25519 keypair
register_agentRegister an agent with a public key + inbox
verify_inboxSubmit a verification challenge code
lookup_agentLook up an agent by inbox email
sign_emailHash + sign + record a message in one step
verify_emailVerify a message's Eleidon signature
hash_messageHash a message using the canonical format
sign_hashSign a pre-computed message hash

CLI

# Generate a keypair
npx @eleidon/cli keygen

# Register an agent
npx @eleidon/cli register --public-key <hex> --inbox agent@company.com

# Verify inbox
npx @eleidon/cli verify-inbox --agent-id <uuid> --code AB3K7M

# Sign a message
npx @eleidon/cli sign --agent-id <uuid> --private-key <hex> \
  --from agent@company.com --to user@example.com \
  --subject "Hello" --body "Message body" --timestamp 2026-01-15T10:30:00Z

# Verify a message
npx @eleidon/cli verify --sender agent@company.com \
  --hash <message_hash> --header "v1:..."

# Look up an agent
npx @eleidon/cli lookup --inbox agent@company.com

Key Management

Private keys are never sent to the API. All signing happens client-side. The API only receives the public key during registration and verifies signatures against it.

Best Practices

Eleidon Header Format

The signature header attached to messages follows this format:

X-Eleidon-Signature: v1:<agent_id>:<signature_id>:<signature_hex>
PartDescription
v1Protocol version
agent_idUUID of the registered agent
signature_idUUID of the recorded signature
signature_hex128-char hex Ed25519 signature

Verification Results

ResultConfidenceMeaning
verified1.0Valid signature from agent with verified inbox
verified0.7Valid signature but inbox not yet verified
unknown0.0No registered agent found
fraudulent1.0Signature invalid, sender mismatch, or header malformed

Agent Lookup Behavior

There are two ways to look up an agent, and they behave differently:

EndpointReturnsUse case
GET /v1/agents/:id Any non-revoked agent, even if inbox is not yet verified Check registration status, see if inbox verification is still pending
GET /v1/agents?inbox=... Only agents with a verified claimed inbox Look up the trusted agent for a given email address before verifying a message

If you look up by inbox and get a 404, it means either no agent has claimed that inbox, the agent hasn't completed inbox verification yet, or the agent has been revoked.