EqhoIDs Developer Documentation

EqhoIDs gives your AI agents a real-world identity. Create agents that can send and receive messages over Telegram, Email, and Webhooks — all through a single, unified REST API.

Base URL

All API requests use the base URL: https://api.eqhoids.com/v1

How It Works

  1. Register an account and get your API key
  2. Create an Agent with the channels you need (Telegram, Email, etc.)
  3. Connect Channels — link a Telegram bot, get an auto-generated email address
  4. Send & Receive Messages through the unified Messages API
  5. Get Webhooks when your agent receives inbound messages

Features

Authentication

All API requests require authentication via an API key or a JWT bearer token. You receive both when you register. The API key is permanent (until regenerated); the JWT token is for session-based access from the dashboard.

API Key Authentication

Pass your API key in the X-API-Key header:

HTTP Header
X-API-Key: eqho_sk_a1b2c3d4e5f6...

Bearer Token Authentication

Alternatively, use the JWT token from /v1/auth/login:

HTTP Header
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Keep Your API Key Secret

Never expose your API key in client-side code or public repositories. If compromised, regenerate it immediately via POST /v1/auth/regenerate-key.

Quick Start

Get up and running in under 5 minutes. Register, create an agent, and send your first message.

Step 1: Register

bash
curl -X POST https://api.eqhoids.com/v1/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "password": "your-secure-password"
  }'
python
import requests

resp = requests.post("https://api.eqhoids.com/v1/auth/register", json={
    "email": "[email protected]",
    "password": "your-secure-password"
})
data = resp.json()
api_key = data["api_key"]  # Save this!
print(f"API Key: {api_key}")
javascript
const resp = await fetch("https://api.eqhoids.com/v1/auth/register", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    email: "[email protected]",
    password: "your-secure-password"
  })
});
const { api_key } = await resp.json();
console.log("API Key:", api_key);  // Save this!

Response

json
{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "api_key": "eqho_sk_a1b2c3d4e5f6...",
  "email_verified": false,
  "message": "Verification code sent to your email."
}
Email Verification

After registering, check your email for a 6-digit verification code. Verify with POST /v1/auth/verify to activate full account access.

Step 2: Create an Agent

bash
curl -X POST https://api.eqhoids.com/v1/agents \
  -H "X-API-Key: eqho_sk_a1b2c3d4e5f6..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "SupportBot",
    "description": "Customer support AI agent",
    "channels": ["telegram", "email"],
    "webhook_url": "https://your-server.com/webhook",
    "webhooks_enabled": false
  }'

Response

json
{
  "id": "agt_8f3a2b1c...",
  "name": "SupportBot",
  "email_address": "[email protected]",
  "email_enabled": true,
  "telegram_enabled": true,
  "telegram_bot_username": null,
  "webhooks_enabled": false,
  "webhook_url": "https://your-server.com/webhook",
  "is_active": true,
  "created_at": "2026-02-15T12:00:00Z",
  "updated_at": "2026-02-15T12:00:00Z"
}

Step 3: Connect Telegram (Optional)

If your agent uses Telegram, connect a bot token from @BotFather:

bash
curl -X POST "https://api.eqhoids.com/v1/agents/{agent_id}/telegram/connect?bot_token=123456:ABC..." \
  -H "X-API-Key: eqho_sk_a1b2c3d4e5f6..."

Step 4: Send Your First Message

bash
curl -X POST https://api.eqhoids.com/v1/messages/send \
  -H "X-API-Key: eqho_sk_a1b2c3d4e5f6..." \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agt_8f3a2b1c...",
    "channel": "telegram",
    "to": "123456789",
    "content": "Hello from EqhoIDs!"
  }'

Agents API

Agents are the core resource in EqhoIDs. Each agent represents an AI identity with its own email address, Telegram bot, and channel configuration.

Create Agent

POST /v1/agents Create a new agent identity

Request Body

name * string Display name for the agent (e.g. "SupportBot")
description string Optional description of the agent's purpose
channels string[] Channels to enable: "telegram", "email". Default: ["telegram"]
webhook_url string URL to receive inbound message events via webhook
webhooks_enabled boolean Enable webhooks for outbound messages. Default: false
bash
curl -X POST https://api.eqhoids.com/v1/agents \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "OrderBot",
    "channels": ["telegram", "email"],
    "webhook_url": "https://example.com/hook",
    "webhooks_enabled": true
  }'

List Agents

GET /v1/agents List all agents for the authenticated user
bash
curl https://api.eqhoids.com/v1/agents \
  -H "X-API-Key: $API_KEY"

Get Agent

GET /v1/agents/{agent_id} Get a single agent by ID

Update Agent

PATCH /v1/agents/{agent_id} Update agent properties

Request Body

All fields are optional. Only include the fields you want to change.

name string New display name
description string New description
webhook_url string New webhook URL
webhooks_enabled boolean Toggle webhooks capability
is_active boolean Deactivate or reactivate the agent
bash
curl -X PATCH https://api.eqhoids.com/v1/agents/agt_8f3a2b1c \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"webhooks_enabled": true}'

Delete Agent

DELETE /v1/agents/{agent_id} Soft-delete an agent (sets is_active to false)
bash
curl -X DELETE https://api.eqhoids.com/v1/agents/agt_8f3a2b1c \
  -H "X-API-Key: $API_KEY"

Returns 204 No Content on success. The agent is soft-deleted and its Telegram webhook is removed.

Connect Telegram Bot

POST /v1/agents/{agent_id}/telegram/connect Connect a Telegram bot to this agent

Query Parameters

bot_token * string Your Telegram bot token from @BotFather
What Happens

EqhoIDs validates your bot token, then sets the Telegram webhook to our endpoint. All incoming messages to your bot will be routed through EqhoIDs and forwarded to your webhook URL.

Response

json
{
  "status": "connected",
  "bot_username": "@YourBotName",
  "webhook_url": "https://api.eqhoids.com/v1/telegram/webhook/agt_8f3a2b1c"
}

Messages API

Send and retrieve messages across all channels with a single, unified interface.

Send Message

POST /v1/messages/send Send a message through any channel

Request Body

agent_id * string The agent sending the message
channel * string "telegram" or "email"
to * string Recipient: Telegram chat ID, email address, or phone number
content * string Message body. For email: first line = subject, rest = body
webhooks boolean Send as a webhook notification. Requires webhooks_enabled on the agent. Default: false
bash
curl -X POST https://api.eqhoids.com/v1/messages/send \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agt_8f3a2b1c",
    "channel": "telegram",
    "to": "123456789",
    "content": "Your order #1234 has been shipped!"
  }'
bash
# For email: first line = subject, rest = body
curl -X POST https://api.eqhoids.com/v1/messages/send \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agt_8f3a2b1c",
    "channel": "email",
    "to": "[email protected]",
    "content": "Order Shipped!\nHi! Your order #1234 has been shipped and will arrive in 2-3 days."
  }'

Response

json — 201 Created
{
  "id": "msg_f7e2d1c0...",
  "agent_id": "agt_8f3a2b1c",
  "channel": "telegram",
  "direction": "outbound",
  "to_id": "123456789",
  "content": "Your order #1234 has been shipped!",
  "content_type": "text",
  "created_at": "2026-02-15T12:30:00Z"
}

List Messages

GET /v1/messages Retrieve message history for an agent

Query Parameters

agent_id * string Filter messages by agent ID
channel string Filter by channel: telegram, email
limit integer Number of messages to return. Default: 50, Max: 200
offset integer Offset for pagination. Default: 0
bash
curl "https://api.eqhoids.com/v1/messages?agent_id=agt_8f3a2b1c&channel=telegram&limit=20" \
  -H "X-API-Key: $API_KEY"

Webhooks

Send signed webhooks powered by cryptographic signing. When you send a message with webhooks: true, EqhoIDs converts the text to speech and delivers it as a webhooks message on the target channel.

Prerequisites

Send a Webhooks Message

bash
curl -X POST https://api.eqhoids.com/v1/messages/send \
  -H "X-API-Key: $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "agt_8f3a2b1c",
    "channel": "telegram",
    "to": "123456789",
    "content": "Hello! Your appointment is confirmed for tomorrow at 3 PM.",
    "webhooks": true
  }'
python
from eqhoids import EqhoIDs

client = EqhoIDs(api_key="eqho_sk_...")

# Send a webhooks message via Telegram
msg = client.messages.send(
    agent_id="agt_8f3a2b1c",
    channel="telegram",
    to="123456789",
    content="Your order is ready for pickup!",
    webhooks=True
)
print(msg.id, msg.content_type)  # "webhooks"
How It Works

When webhooks: true is set, EqhoIDs sends the payload to the configured webhook endpoint. generates an OGG audio file, and sends it as a webhooks message via the Telegram Bot API.

Webhooks

Receive real-time notifications when your agent gets an inbound message. EqhoIDs will POST a JSON payload to your agent's webhook_url whenever a message arrives on any channel.

Webhook Payload

Each webhook delivery contains the following structure:

json — Telegram inbound
{
  "event": "message.received",
  "agent_id": "agt_8f3a2b1c",
  "data": {
    "channel": "telegram",
    "from": {
      "id": "123456789",
      "username": "johndoe",
      "first_name": "John"
    },
    "message": {
      "id": "msg_abc123",
      "text": "Hi, I need help with my order",
      "telegram_message_id": 42
    }
  }
}
json — Email inbound
{
  "event": "message.received",
  "agent_id": "agt_8f3a2b1c",
  "data": {
    "channel": "email",
    "from": "[email protected]",
    "from_name": "John Doe",
    "to": "[email protected]",
    "subject": "Question about my order",
    "body": "Hi, when will my order arrive?",
    "body_html": "<p>Hi, when will my order arrive?</p>"
  }
}

Webhook Headers

Every webhook request includes these headers:

HeaderDescription
Content-Typeapplication/json
X-EqhoIDs-EventEvent type, e.g. message.received
X-EqhoIDs-SignatureHMAC-SHA256 hex digest of the payload, signed with your agent's webhook secret

Signature Verification

Always verify the X-EqhoIDs-Signature header to ensure the webhook came from EqhoIDs. The signature is an HMAC-SHA256 hash of the raw JSON body, using your agent's webhook_secret as the key.

python
import hmac, hashlib

def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

# In your Flask/FastAPI handler:
signature = request.headers.get("X-EqhoIDs-Signature")
if not verify_webhook(request.body, signature, WEBHOOK_SECRET):
    return "Unauthorized", 401
javascript
const crypto = require("crypto");

function verifyWebhook(payload, signature, secret) {
  const expected = crypto
    .createHmac("sha256", secret)
    .update(payload)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

// In your Express handler:
app.post("/webhook", (req, res) => {
  const sig = req.headers["x-eqhoids-signature"];
  if (!verifyWebhook(req.rawBody, sig, WEBHOOK_SECRET)) {
    return res.status(401).send("Unauthorized");
  }
  // Process the event...
});

Retry Behavior

If your webhook endpoint returns a non-2xx status code or times out, EqhoIDs will retry delivery with exponential backoff:

AttemptDelayTotal Elapsed
1stImmediate0s
2nd1 second~1s
3rd (final)3 seconds~4s

After 3 failed attempts, the delivery is marked as failed and logged. The webhook timeout is 10 seconds per attempt.

Respond Quickly

Your webhook endpoint should respond with a 200 status within 10 seconds. Process the event asynchronously if needed, and acknowledge receipt immediately.

Email

Every agent automatically gets a unique email address in the format {name}-{random}@agent.eqhoids.com. Inbound emails are processed and forwarded to your webhook as message.received events.

How Inbound Email Works

  1. Someone sends an email to your agent's address (e.g. [email protected])
  2. Cloudflare Email Workers receive the email and forward it to EqhoIDs
  3. EqhoIDs stores the message and delivers a webhook to your webhook_url
  4. You process the email and respond via POST /v1/messages/send with channel: "email"

Sending Emails

When sending via the email channel, the first line of content becomes the email subject, and the rest becomes the body:

python
client.messages.send(
    agent_id="agt_8f3a2b1c",
    channel="email",
    to="[email protected]",
    content="Re: Your Order Status\nHi! Your order #1234 shipped today.\n\nBest,\nSupportBot"
)

Telegram Integration

Connect your own Telegram bot to an EqhoIDs agent. EqhoIDs handles webhook routing, message storage, and forwarding to your application.

Setup Steps

  1. Create a bot with @BotFather on Telegram
  2. Copy the bot token (e.g. 123456:ABCdefGHI...)
  3. Call POST /v1/agents/{id}/telegram/connect?bot_token=YOUR_TOKEN
  4. EqhoIDs validates the token and sets the webhook automatically

Message Flow

Inbound: User messages your bot → Telegram sends update to EqhoIDs → EqhoIDs stores message → Webhook delivered to your URL

Outbound: You call POST /v1/messages/send → EqhoIDs sends via Telegram Bot API → User receives the message

Getting the Chat ID

The to field for Telegram is the chat ID (numeric string). You can get it from the inbound webhook payload (data.from.id) when a user messages your bot first.

Billing & Plans

EqhoIDs offers three plans. All plans include email and Telegram channels. Payments are processed by Paddle (Merchant of Record), handling all tax and compliance.

Starter

$19/mo
  • 1 agent
  • 500 messages/mo
  • Telegram + Email
  • 30-day history
  • Webhook delivery

Business

$99/mo
  • 25 agents
  • 25,000 messages/mo
  • All channels
  • Webhooks enabled
  • Unlimited history

Billing API Endpoints

GET /v1/billing/plans List all available plans with pricing
GET /v1/billing/subscription Get current subscription status and usage
POST /v1/billing/checkout?plan={plan} Create a Paddle checkout session for upgrading

Usage Tracking

GET /v1/analytics/usage Get detailed usage breakdown by channel
json — Usage response
{
  "plan": "pro",
  "agents": { "active": 3, "limit": 5 },
  "messages": {
    "used": 1247,
    "limit": 5000,
    "by_channel": {
      "telegram": { "inbound": 520, "outbound": 480 },
      "email": { "inbound": 130, "outbound": 117 }
    }
  }
}

Rate Limits

Rate limits are enforced per API key (or IP for unauthenticated requests) using a sliding window algorithm. Limits vary by endpoint type.

Endpoint Type Limit Window Example Endpoints
Authentication 10 requests 60 seconds /v1/auth/*
General API 60 requests 60 seconds /v1/agents, /v1/messages (GET), /v1/analytics
Message Sending 30 requests 60 seconds /v1/messages/send
Webhooks (inbound) 120 requests 60 seconds /v1/telegram/webhook/*, /v1/email/inbound

Rate Limit Headers

Every response includes rate limit information:

HeaderDescription
X-RateLimit-LimitMaximum requests allowed in the window
X-RateLimit-RemainingRequests remaining in the current window
X-RateLimit-ResetUnix timestamp when the window resets

Handling 429 Errors

When you exceed the rate limit, you'll receive a 429 Too Many Requests response with a Retry-After header:

python
import time, requests

def send_with_retry(url, headers, data, max_retries=3):
    for attempt in range(max_retries):
        resp = requests.post(url, headers=headers, json=data)
        if resp.status_code == 429:
            retry_after = int(resp.headers.get("Retry-After", 60))
            time.sleep(retry_after)
            continue
        return resp
    raise Exception("Rate limit exceeded after retries")

Error Codes

All errors follow a consistent JSON format with an HTTP status code and a detail message.

json — Error response format
{
  "detail": "Agent not found"
}
Status Meaning Common Causes
400 Bad Request Invalid JSON, missing required fields, invalid Telegram bot token, unsupported channel
401 Unauthorized Missing or invalid API key / bearer token, wrong credentials on login
403 Forbidden Agent limit reached (upgrade plan), invalid webhook signature
404 Not Found Agent ID doesn't exist or belongs to another user, unknown email recipient
409 Conflict Email already registered
422 Validation Error Request body doesn't match expected schema (FastAPI auto-validation)
429 Rate Limited Too many requests. Check Retry-After header
500 Server Error Internal error. Failed to send Telegram message, failed to set webhook, webhook delivery failure
502 Bad Gateway Paddle API error during checkout
504 Gateway Timeout Paddle API timeout during checkout

Validation Errors (422)

FastAPI returns detailed validation errors with the field location and error type:

json
{
  "detail": [
    {
      "loc": ["body", "name"],
      "msg": "field required",
      "type": "value_error.missing"
    }
  ]
}

SDKs

Official client libraries to integrate EqhoIDs into your application.

Python SDK

bash
pip install eqhoids
python
from eqhoids import EqhoIDs

client = EqhoIDs(api_key="eqho_sk_...")

# Create an agent
agent = client.agents.create(
    name="SupportBot",
    channels=["telegram", "email"],
    webhook_url="https://example.com/webhook"
)
print(f"Agent: {agent.id}, Email: {agent.email_address}")

# Send a message
msg = client.messages.send(
    agent_id=agent.id,
    channel="telegram",
    to="123456789",
    content="Hello from EqhoIDs!"
)

# List messages
messages = client.messages.list(agent_id=agent.id, limit=20)
for m in messages:
    print(f"[{m.direction}] {m.content}")

# Check usage
usage = client.analytics.usage()
print(f"Messages: {usage['messages']['used']}/{usage['messages']['limit']}")

Source: github.com/eqho10/eqhoids-python

Node.js SDK

bash
npm install eqhoids
javascript
import { EqhoIDs } from "eqhoids";

const client = new EqhoIDs({ apiKey: "eqho_sk_..." });

// Create an agent
const agent = await client.agents.create({
  name: "SupportBot",
  channels: ["telegram", "email"],
  webhookUrl: "https://example.com/webhook"
});
console.log(`Agent: ${agent.id}, Email: ${agent.emailAddress}`);

// Send a message
const msg = await client.messages.send({
  agentId: agent.id,
  channel: "telegram",
  to: "123456789",
  content: "Hello from EqhoIDs!"
});

// List messages
const messages = await client.messages.list({ agentId: agent.id });
messages.forEach(m => console.log(`[${m.direction}] ${m.content}`));

// Check usage
const usage = await client.analytics.usage();
console.log(`Messages: ${usage.messages.used}/${usage.messages.limit}`);

Source: github.com/eqho10/eqhoids-node


Full API Reference

For a complete, interactive API reference, see the auto-generated Swagger UI or ReDoc documentation, or download the Postman Collection for offline testing.