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.
All API requests use the base URL: https://api.eqhoids.com/v1
How It Works
- Register an account and get your API key
- Create an Agent with the channels you need (Telegram, Email, etc.)
- Connect Channels — link a Telegram bot, get an auto-generated email address
- Send & Receive Messages through the unified Messages API
- Get Webhooks when your agent receives inbound messages
Features
- Multi-Channel: Telegram, Email, Webhooks — one API for all
- Agent Identities: Each agent gets its own email, Telegram bot, and more
- Webhooks: Send signed webhooks powered by cryptographic signing
- Webhooks: Real-time inbound message delivery with signature verification
- Usage Analytics: Track message counts and channel usage per agent
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:
X-API-Key: eqho_sk_a1b2c3d4e5f6...
Bearer Token Authentication
Alternatively, use the JWT token from /v1/auth/login:
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
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
curl -X POST https://api.eqhoids.com/v1/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"password": "your-secure-password"
}'
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}")
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
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"api_key": "eqho_sk_a1b2c3d4e5f6...",
"email_verified": false,
"message": "Verification code sent to your email."
}
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
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
{
"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:
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
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
Request Body
"telegram", "email". Default: ["telegram"]
false
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
curl https://api.eqhoids.com/v1/agents \
-H "X-API-Key: $API_KEY"
Get Agent
Update Agent
Request Body
All fields are optional. Only include the fields you want to change.
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
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
Query Parameters
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
{
"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
Request Body
"telegram" or "email"
webhooks_enabled on the agent. Default: false
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!"
}'
# 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
{
"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
Query Parameters
telegram, email
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
- The agent must have
webhooks_enabled: true - Webhooks is available on Pro and Business plans
- Currently supported on the Telegram channel
Send a Webhooks Message
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
}'
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"
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:
{
"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
}
}
}
{
"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:
| Header | Description |
|---|---|
Content-Type | application/json |
X-EqhoIDs-Event | Event type, e.g. message.received |
X-EqhoIDs-Signature | HMAC-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.
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
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:
| Attempt | Delay | Total Elapsed |
|---|---|---|
| 1st | Immediate | 0s |
| 2nd | 1 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.
Your webhook endpoint should respond with a 200 status within 10 seconds.
Process the event asynchronously if needed, and acknowledge receipt immediately.
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
- Someone sends an email to your agent's address (e.g.
[email protected]) - Cloudflare Email Workers receive the email and forward it to EqhoIDs
- EqhoIDs stores the message and delivers a webhook to your
webhook_url - You process the email and respond via
POST /v1/messages/sendwithchannel: "email"
Sending Emails
When sending via the email channel, the first line of content
becomes the email subject, and the rest becomes the body:
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
- Create a bot with @BotFather on Telegram
- Copy the bot token (e.g.
123456:ABCdefGHI...) - Call
POST /v1/agents/{id}/telegram/connect?bot_token=YOUR_TOKEN - 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
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
- 1 agent
- 500 messages/mo
- Telegram + Email
- 30-day history
- Webhook delivery
Pro
- 5 agents
- 5,000 messages/mo
- Telegram + Email
- Webhooks enabled
- 90-day history
Business
- 25 agents
- 25,000 messages/mo
- All channels
- Webhooks enabled
- Unlimited history
Billing API Endpoints
Usage Tracking
{
"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:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed in the window |
X-RateLimit-Remaining | Requests remaining in the current window |
X-RateLimit-Reset | Unix 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:
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.
{
"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:
{
"detail": [
{
"loc": ["body", "name"],
"msg": "field required",
"type": "value_error.missing"
}
]
}
SDKs
Official client libraries to integrate EqhoIDs into your application.
Python SDK
pip install eqhoids
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
npm install eqhoids
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.