echloe.io

API Reference

Integrate Echloe's GEO audit, content generation, and keyword discovery into your own applications.

Authentication

All API requests require a valid API key passed in the Authorization header as a Bearer token.

API keys start with ek_live_ and can be generated in your Dashboard Settings.

bashcurl https://echloe.io/api/v1/audit \
  -H "Authorization: Bearer ek_live_abc123def456..." \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'

Base URL

https://echloe.io/api/v1

Rate Limits

EndpointLimit
POST /api/v1/audit10 requests per day per API key
POST /api/v1/contentNo hard limit (fair use)
POST /api/v1/keywordsNo hard limit (fair use)

When rate limited, the API returns 429 Too Many Requests.


Run GEO Audit

POST/api/v1/audit

Runs a comprehensive GEO (Generative Engine Optimization) audit on the given URL. Returns a detailed score with per-category breakdowns, findings, and recommendations.

Request Body

ParameterTypeRequiredDescription
urlstringYesThe URL to audit (with or without https://)

Example

bashcurl -X POST https://echloe.io/api/v1/audit \
  -H "Authorization: Bearer ek_live_..." \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com"}'

Response

json{
  "url": "https://example.com/",
  "score": 42,
  "categories": [
    {
      "name": "AI Citability",
      "score": 12,
      "maxScore": 25,
      "weight": 25,
      "details": "Average passage citability: 48/100..."
    }
  ],
  "findings": [
    {
      "severity": "critical",
      "category": "Schema & Structured Data",
      "message": "No JSON-LD structured data found."
    }
  ],
  "recommendations": [
    {
      "priority": 1,
      "title": "Fix: No JSON-LD structured data found",
      "description": "...",
      "impact": "high"
    }
  ],
  "crawledAt": "2026-04-02T12:00:00.000Z",
  "citability": { "averageScore": 48, "blockCount": 12, ... },
  "brandPresence": { "platforms": { ... }, "overallScore": 35 },
  "crawlerAccess": { "tier1Allowed": 5, "tier2Allowed": 7, ... },
  "llmsTxt": { "exists": false, ... },
  "schemaReport": { "typesFound": ["Organization"], ... }
}

Generate Content

POST/api/v1/content

Generates AI content (currently blog posts) for a product. The content is stored in your account and returned in the response.

Request Body

ParameterTypeRequiredDescription
productIdstringYesID of the product to generate content for
topicstringYesThe topic or keyword to write about
typestringYesContent type. Currently only "blog_post" is supported.

Example

bashcurl -X POST https://echloe.io/api/v1/content \
  -H "Authorization: Bearer ek_live_..." \
  -H "Content-Type: application/json" \
  -d '{"productId": "abc123", "topic": "AI SEO best practices", "type": "blog_post"}'

Response

json{
  "id": "ctn_xyz789",
  "title": "AI SEO Best Practices for 2026",
  "content": "# AI SEO Best Practices for 2026\n\n..."
}

List Content

GET/api/v1/content

Returns a paginated list of your generated content pieces.

Query Parameters

ParameterTypeRequiredDescription
limitintegerNoMax items to return (default 20, max 100)
offsetintegerNoNumber of items to skip (default 0)

Example

bashcurl "https://echloe.io/api/v1/content?limit=10" \
  -H "Authorization: Bearer ek_live_..."

Response

json{
  "items": [
    {
      "id": "...",
      "title": "AI SEO Best Practices",
      "type": "blog_post",
      "status": "draft",
      "tokenCount": 2048,
      "createdAt": "2026-04-01T10:00:00.000Z"
    }
  ],
  "limit": 10,
  "offset": 0
}

Discover Keywords

POST/api/v1/keywords

Uses AI to discover up to 20 new keywords for a product. Discovered keywords are automatically stored and won't be repeated on subsequent calls.

Request Body

ParameterTypeRequiredDescription
productIdstringYesID of the product to discover keywords for

Example

bashcurl -X POST https://echloe.io/api/v1/keywords \
  -H "Authorization: Bearer ek_live_..." \
  -H "Content-Type: application/json" \
  -d '{"productId": "abc123"}'

Response

json{
  "keywords": [
    {
      "id": "kw_001",
      "keyword": "ai content optimization",
      "intent": "informational",
      "difficulty": "medium",
      "source": "ai_discovered",
      "status": "active"
    }
  ],
  "count": 18
}

List Keywords

GET/api/v1/keywords

Returns all keywords for a given product.

Query Parameters

ParameterTypeRequiredDescription
productIdstringYesProduct ID to list keywords for

Example

bashcurl "https://echloe.io/api/v1/keywords?productId=abc123" \
  -H "Authorization: Bearer ek_live_..."

Webhooks

Echloe can send real-time notifications to your server when events occur. Configure webhook endpoints in your Dashboard Settings.

Events

EventDescription
audit.completedA GEO audit has finished processing
content.publishedContent has been generated
keyword.discoveredNew keywords have been discovered

Payload Format

json{
  "event": "audit.completed",
  "timestamp": "2026-04-02T12:00:00.000Z",
  "data": {
    "url": "https://example.com",
    "score": 72,
    "auditId": "https://example.com/"
  }
}

Headers

HeaderDescription
X-Echloe-SignatureHMAC-SHA256 hex digest of the raw request body
X-Echloe-EventThe event name (e.g. audit.completed)

Signature Verification

Each webhook request includes an X-Echloe-Signature header containing an HMAC-SHA256 signature of the raw request body, signed with your webhook secret.

javascriptconst crypto = require('crypto');

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

// In your webhook handler:
app.post('/webhook', (req, res) => {
  const signature = req.headers['x-echloe-signature'];
  const event = req.headers['x-echloe-event'];

  if (!verifyWebhook(req.rawBody, signature, WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  const payload = JSON.parse(req.rawBody);
  console.log('Received ' + event + ':', payload.data);
  res.status(200).send('OK');
});

Error Handling

StatusMeaning
400Bad request — missing or invalid parameters
401Unauthorized — invalid or missing API key
404Resource not found
429Rate limit exceeded
500Internal server error

All errors return JSON:

json{
  "error": "Human-readable error message"
}

Need help? [email protected]