AI Directories

official

Search the AI Directories catalog, look up a listing, and browse submission directories

What can you do with AI Directories MCP?

  • Search AI tools — Ask to find AI tools by keyword, category, tag, or pricing using search_tools.
  • Fetch tool details — Request the full public listing for any tool by slug via get_tool, including screenshots and FAQs.
  • Browse top tools — Ask for the most popular AI tools by opens, optionally filtered by category, with get_top_tools.
  • Explore categories and tags — Have the assistant list all AI tool categories or tags with counts using list_categories or list_tags.
  • Find submission directories — Search directories by name, cost, or category with search_directories to identify submission targets.
  • Get directory profiles — Retrieve a directory's full profile, including Domain Rating and badge requirements, via get_directory.

Documentation

Developers

Open in Claude

API & MCP

Official AI Directories catalog — search AI tools and submission directories from curl or an agent. Free, documented, and better than scraping.

RESTGET · Bearer aid_

www.aidirectori.es/api/v1

MCPStreamable HTTP

api/mcp

OpenAPImachine spec

openapi.json

Search the AI Directories catalog, look up a listing, and browse submission directories — from an agent or from curl. REST and MCP share the same backend. Third-party scrapers wrap our public pages and charge for a dump. This is the official source.

Example — GET /tools/transclipper

curl -s "https://www.aidirectori.es/api/v1/tools/transclipper" \
  -H "Authorization: Bearer aid_your_api_key"
{
  "success": true,
  "data": {
    "id": "69b81f3e40816562014e004a",
    "slug": "transclipper",
    "name": "TransClipper",
    "url": "https://www.aidirectori.es/ai-tools/transclipper",
    "website": "https://transclipper.ai",
    "tagline": "Steal the Blueprint Behind Any Viral Video",
    "description": "TransClipper is a powerful AI-driven tool designed for efficient content clipping and transcription.",
    "category": { "slug": "video", "name": "Video" },
    "tags": [
      { "slug": "ai", "name": "AI" },
      { "slug": "content-creation", "name": "Content Creation" }
    ],
    "pricing": "FREE",
    "rating": 4,
    "opens": 4030,
    "featured": true,
    "icon": "https://cdn.aidirectori.es/icons/1784893027853-vpj1hwsqkq.png"
  }
}

What you can do

  • Search AI tools by keyword, category, tag, or pricing
  • Fetch one tool by slug (full public listing)
  • List categories and tags
  • Search submission directories (DR, cost, badge)
  • Fetch one directory profile with your aid_ key

What you cannot do

  • Read founder emails or private analytics
  • Scrape the HTML site or impersonate a crawler
  • Republish the catalog as a competing directory
  • Call partner write APIs without an issued key

Why this exists

People were scraping aidirectori.es and selling the export. The official API is free for products, research, and agents — with attribution, rate limits, and a license: you may not republish the full catalog as a competing directory or paid scrape.

Drop into an agent

Cursor: .cursor/mcp.json or ~/.cursor/mcp.json. No space after Authorization: — mcp-remote splits on whitespace. See Install MCP.

{
  "mcpServers": {
    "aidirectories": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote",
        "https://www.aidirectori.es/api/mcp",
        "--header", "Authorization:Bearer aid_your_real_key"
      ]
    }
  }
}

Also machine-readable

Get started / Quickstart

Quickstart

Create an aid_ key, then search tools, fetch one listing, and search directories.

Create a key on the developer dashboard, then copy these.

1. Search AI tools

curl -s "https://www.aidirectori.es/api/v1/tools?q=image&limit=5" \
  -H "Authorization: Bearer aid_your_api_key"

2. Fetch one listing

curl -s "https://www.aidirectori.es/api/v1/tools/transclipper" \
  -H "Authorization: Bearer aid_your_api_key"

3. Search directories

curl -s "https://www.aidirectori.es/api/v1/directories?q=ai&limit=5" \
  -H "Authorization: Bearer aid_your_api_key"

Same operations over MCP: add the server with the same Bearer token, then call search_tools, get_tool, and search_directories. See MCP install.

Get started / Authentication

Authentication

Bearer token via API key. Generate keys from your developer dashboard. Standard 10/min, premium 60/min.

Authentication

Bearer token via API key. Generate keys from your developer dashboard.

Rate limits

Standard keys get 10 requests per minute. Premium keys get 60. Upgrade from your developer dashboard. Rate-limit headers are on every response.

Base URL

https://www.aidirectori.es/api/v1

  1. 1 Get your API key

    Go to the developer dashboard and create an API key. Keys start with aid_. Store it securely — you won't be able to see the full key again. Acceptable use is required Creating a key requires agreement to the API Acceptable Use Policy. Cloning businesses, rebuilding AI Directories, bulk republication, unauthorized public SEO pages, abusive targeting, credential sharing, and access-control evasion are prohibited and can result in a permanent platform ban.
  2. 2 Make your first request

    Pass your key as a Bearer token in the Authorization header. X-API-Key is also accepted, on every endpoint. The two are interchangeable — what a key can reach depends on the key, not the header it arrives in. A dashboard aid_ key still gets 403 on the partner endpoints when sent as X-API-Key; if you are seeing 403, you need a different key, not a different header.
    curl -s "https://www.aidirectori.es/api/v1/tools?q=ai&limit=5" \
      -H "Authorization: Bearer aid_your_api_key"
    
  3. 3 Parse the response

    Successful reads return { success: true, data }. List endpoints also include pagination — its fields and the limit-clamping rules are worth reading before you write a paging loop. Watch X-RateLimit-Remaining.
    {
      "success": true,
      "data": [
        {
          "slug": "transclipper",
          "name": "TransClipper",
          "website": "https://transclipper.ai"
        }
      ]
    }
    

Partner keys

Directory partners who send us tools for the submission service still use an issued key for POST /submit-ai-tool, status, webhooks, and support. Those keys also work on catalog reads. See Got a directory?.

MCP / Install

Install MCP

Hosted Streamable HTTP MCP — send the same Bearer key as REST.

The server speaks the Model Context Protocol over Streamable HTTP. It is hosted. Every tool wraps the same functions as the REST API. Send Authorization: Bearer aid_… from your developer dashboard.

https://www.aidirectori.es/api/mcp

Claude Code

claude mcp add --transport http aidirectories https://www.aidirectori.es/api/mcp \
  --header "Authorization: Bearer aid_your_api_key"

Cursor / Claude Desktop

Project scope: .cursor/mcp.json. Global: ~/.cursor/mcp.json. Claude Desktop: claude_desktop_config.json (stdio only — this same block).

{
  "mcpServers": {
    "aidirectories": {
      "command": "npx",
      "args": [
        "-y", "mcp-remote",
        "https://www.aidirectori.es/api/mcp",
        "--header", "Authorization:Bearer aid_your_real_key"
      ]
    }
  }
}

No space after Authorization: — mcp-remote splits arguments on whitespace, so "Authorization: Bearer …" breaks the header. Restart the client fully after editing the file.

After adding the server, ask the agent to list tools. You should see search_tools, get_top_tools, get_tool, list_categories, list_tags, search_directories, get_directory, and list_directory_categories.

Verify

curl -s https://www.aidirectori.es/api/mcp -X POST \
  -H "Authorization: Bearer aid_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}'

MCP / Tools

MCP tools

Every MCP tool is a thin wrapper over the REST catalog.

Auth is the same Bearer aid_ key as REST.

ToolRESTInput
search_toolsGET /toolsq, category, tag, pricing, featured, page, limit
get_top_toolsGET /tools/toplimit, category
get_toolGET /tools/{slug}slug
list_categoriesGET /categoriesq, limit
list_tagsGET /tagsq, limit
search_directoriesGET /directoriesq, category, cost, featured, page, limit
get_directoryGET /directories/{slug}slug
list_directory_categoriesGET /directory-categories—

Full field notes live under AI tools and Directories.

REST API / Overview

REST API

Plain HTTP for scripts, CI, and partner integrations. The MCP server calls these same paths — so a result never depends on which transport asked for it.

OperationMethodPathAuthInput
search_tools Keyword search with optional category, tag, pricing, and featured filters.GET/toolsBearerq, category, tag, pricing, featured, includeAdult, page, limit
get_top_tools Top N listings by opens — no keyword required.GET/tools/topBearerlimit, category, includeAdult
list_categories AI tool categories with tool counts — use before filtering search.GET/categoriesBearerq, limit
list_tags AI tool tags with tool counts.GET/tagsBearerq, limit
get_tool The full public listing for one AI tool.GET/tools/{slug}Bearerslug
search_directories Search submission directories by name, category, or cost.GET/directoriesBearerq, category, cost, featured, page, limit
get_directory The full public profile for one directory.GET/directories/{slug}Bearerslug
list_directory_categories Directory category labels for filter discovery.GET/directory-categoriesBearer—
submit_ai_tool Create an AI tool listing (and optionally queue directory submissions).POST/submit-ai-toolX-API-Keyname, website, tagline, description, category, pricing, founderName, founderEmail, tags, paymentType, …
get_tool_status Poll directory-submission progress for a tool your key submitted.GET/ai-tools/statusX-API-Keyid | slug | website

Discovery lives at GET / and the OpenAPI document at GET /openapi.json. Field notes for catalog responses are on AI tools and Directories.

Envelope, pagination, and limits

Every response is the same envelope. data is an array on searches and an object on single-item lookups. Check success before reading data.

{ "success": true, "data": [], "pagination": { "page": 1, "limit": 20, "total": 0, "pages": 0 } }

{ "success": false, "error": "Invalid or revoked API key." }

GET /tools and GET /directories return a pagination object. The taxonomy endpoints — /categories, /tags, /directory-categories — return the whole list and no pagination key at all.

pageThe page you got, 1-based
limitItems per page actually applied
totalMatching items across all pages
pagesceil(total / limit), or 0 when nothing matched

An oversized limit is clamped, not rejected. Ask for more than the maximum and you get the maximum, with a 200 — no error tells you it happened. /tools and /directories default to 20 and cap at 100; /categories and /tags cap at 500. A missing, zero, negative, or non-numeric limit falls back to the default, and page floors at 1. So read pagination.limit back from the response rather than assuming you got the page size you asked for — that assumption is what turns a paging loop into an infinite one.

page=1
while :; do
  body=$(curl -s "https://www.aidirectori.es/api/v1/tools?limit=100&page=$page" \
    -H "Authorization: Bearer $AID_KEY")
  echo "$body" | jq -e '.success' >/dev/null || { echo "$body"; break; }
  echo "$body" | jq -c '.data[]'
  pages=$(echo "$body" | jq '.pagination.pages')
  [ "$page" -ge "$pages" ] && break
  page=$((page + 1))
  sleep 6   # stay under 10 req/min on a standard key
done

AI tools

Browse, search, and filter the live catalog, or fetch one listing by slug. Maps to MCP search_tools, get_top_tools, get_tool, list_categories, and list_tags.

list_categories

AI tool categories with tool counts — use before filtering search.

RESTGET /categories
MCPtools/call → list_categories
AuthBearer
Inputq, limit
curl -s "https://www.aidirectori.es/api/v1/categories" \
  -H "Authorization: Bearer aid_your_api_key"

get_top_tools

Top N listings by opens — no keyword required.

RESTGET /tools/top
MCPtools/call → get_top_tools
AuthBearer
Inputlimit, category, includeAdult
curl -s "https://www.aidirectori.es/api/v1/tools/top?limit=10&category=image" \
  -H "Authorization: Bearer aid_your_api_key"

search_tools

Keyword search with optional category, tag, pricing, and featured filters.

RESTGET /tools
MCPtools/call → search_tools
AuthBearer
Inputq, category, tag, pricing, featured, includeAdult, page, limit
curl -s "https://www.aidirectori.es/api/v1/tools?q=ai&limit=5" \
  -H "Authorization: Bearer aid_your_api_key"

get_tool

The full public listing for one AI tool.

RESTGET /tools/{slug}
MCPtools/call → get_tool
AuthBearer
Inputslug
curl -s "https://www.aidirectori.es/api/v1/tools/transclipper" \
  -H "Authorization: Bearer aid_your_api_key"

list_tags

AI tool tags with tool counts.

RESTGET /tags
MCPtools/call → list_tags
AuthBearer
Inputq, limit
curl -s "https://www.aidirectori.es/api/v1/tags" \
  -H "Authorization: Bearer aid_your_api_key"

Directories

The submission-directory catalog — Domain Rating, cost, badge, and categories. Maps to MCP search_directories, get_directory, and list_directory_categories.

search_directories

Search submission directories by name, category, or cost.

RESTGET /directories
MCPtools/call → search_directories
AuthBearer
Inputq, category, cost, featured, page, limit
curl -s "https://www.aidirectori.es/api/v1/directories?cost=Free&limit=10" \
  -H "Authorization: Bearer aid_your_api_key"

get_directory

The full public profile for one directory.

RESTGET /directories/{slug}
MCPtools/call → get_directory
AuthBearer
Inputslug
curl -s "https://www.aidirectori.es/api/v1/directories/theres-an-ai-for-that" \
  -H "Authorization: Bearer aid_your_api_key"

list_directory_categories

Directory category labels for filter discovery.

RESTGET /directory-categories
MCPtools/call → list_directory_categories
AuthBearer
Input—
curl -s "https://www.aidirectori.es/api/v1/directory-categories" \
  -H "Authorization: Bearer aid_your_api_key"

Partner

Write and status endpoints need an issued X-API-Key. Keep it on your server. MCP does not call these. Full field lists live under Submit & partners.

submit_ai_tool

Create an AI tool listing (and optionally queue directory submissions).

RESTPOST /submit-ai-tool
MCP—
AuthX-API-Key
Inputname, website, tagline, description, category, pricing, founderName, founderEmail, tags, paymentType, …
curl -s -X POST "https://www.aidirectori.es/api/v1/submit-ai-tool" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Tool",
    "website": "https://mytool.com",
    "tagline": "One-line pitch",
    "description": "What the product does.",
    "category": "productivity",
    "pricing": "FREE",
    "paymentType": "pro",
    "founderName": "Jane Founder",
    "founderEmail": "jane@mytool.com",
    "tags": ["ai", "productivity"],
    "icon": "https://mytool.com/icon.png",
    "frame": "https://mytool.com/screenshot.png",
    "screenshots": ["https://mytool.com/gallery-1.png"]
  }'

get_tool_status

Poll directory-submission progress for a tool your key submitted.

RESTGET /ai-tools/status
MCP—
AuthX-API-Key
Inputid | slug | website
curl -s "https://www.aidirectori.es/api/v1/ai-tools/status?slug=my-ai-tool" \
  -H "X-API-Key: YOUR_API_KEY"

REST API / AI tools

AI tools

Browse, search, and fetch published AI tool listings.

search_tools

Keyword search with category, tag, pricing, and featured filters.

RESTGET /tools
MCPsearch_tools
AuthBearer aid_
Inputq, category, tag, pricing (FREE | FREEMIUM | PAID), featured, includeAdult, page, limit (max 100)
curl -s "https://www.aidirectori.es/api/v1/tools?q=transclipper&limit=5" \
  -H "Authorization: Bearer aid_your_api_key"

Each item includes name, slug, listing URL, website, tagline, description, category, tags, pricing, rating, opens, icon, and timestamps. No founder email.

Adult listings are excluded by default. search_tools and get_top_tools hold back adult listings unless you ask for them.

Exclusion is by category and tag, because adult tools are often filed under a general category — image, writing, video — while tagging themselves accurately. So category=image returns image tools without the undressing apps.

Three ways to opt in: includeAdult=true, category=nsfw, or naming an adult tag such as tag=ai-undressing. Nothing is hidden or unreachable — it is simply not what you get when you did not ask.

get_top_tools

Most opened published tools. Optional category slug.

curl -s "https://www.aidirectori.es/api/v1/tools/top?limit=10&category=image" \
  -H "Authorization: Bearer aid_your_api_key"

get_tool

Full public listing: screenshots, FAQs, socials, features.

curl -s "https://www.aidirectori.es/api/v1/tools/transclipper" \
  -H "Authorization: Bearer aid_your_api_key"

list_categories / list_tags

curl -s "https://www.aidirectori.es/api/v1/categories" -H "Authorization: Bearer aid_your_api_key"
curl -s "https://www.aidirectori.es/api/v1/tags?q=photo" -H "Authorization: Bearer aid_your_api_key"

Categories return slug, name, description, icon, toolsCount. Tags return slug, name, toolsCount. Neither is paginated — you get the whole list, so cache it and filter locally.

Tool fields

Returned by /tools, /tools/top and /tools/{slug} alike:

FieldTypeNotes
idstringStable identifier
slugstringUse this for /tools/{slug}
name, tagline, descriptionstring
urlstringThe listing on aidirectori.es
websitestringThe product's own site
categoryobject{ slug, name }, or null
tagsarray[{ slug, name }]
pricingstringFREE | FREEMIUM | PAID
ratingnumber0 when unrated
opensnumberClick-throughs; what /tools/top sorts by
featuredboolean
icon, framestringImage URLs, nullable
founderName, locationstringNullable. No founder email, ever
domainRatingnumberNullable
isForSale, askingPriceboolean, numberListings marked for acquisition
discountCode, affiliatestring, boolean
createdAt, updatedAtstringISO 8601, nullable

GET /tools/{slug} adds screenshots (array of URLs), video, socials, faqs, features, and affiliateLink. Those six are only on the single-tool endpoint — don't expect them from a search.

Any field can be null when a listing has not filled it in. Code defensively.

REST API / Directories

Directories

The other half of the catalog — startup and SaaS submission directories, with DR and pricing.

Scrapers usually miss this. It is the list we actually submit products to.

search_directories

RESTGET /directories
MCPsearch_directories
AuthBearer aid_
Inputq, category, cost (Free | Paid | Freemium), featured, page, limit
curl -s "https://www.aidirectori.es/api/v1/directories?cost=Free&limit=10" \
  -H "Authorization: Bearer aid_your_api_key"

Fields include name, listing URL, website, Domain Rating, monthly visits, link type, badge requirement, minimum price, and categories.

get_directory

Adds description, FAQ, submission link, and deal copy.

curl -s "https://www.aidirectori.es/api/v1/directories/theres-an-ai-for-that" \
  -H "Authorization: Bearer aid_your_api_key"

list_directory_categories

curl -s "https://www.aidirectori.es/api/v1/directory-categories" \
  -H "Authorization: Bearer aid_your_api_key"

Returns slug and name only. Not paginated. These are the values ?category= accepts — read them rather than guessing.

Directory fields

FieldTypeNotes
id, slug, namestring
urlstringThe profile on aidirectori.es
websitestringThe directory's own site
iconstringNullable
coststringFree | Paid | Freemium
typestringLink type
domainRatingnumberNullable — the number most people sort on
monthlyVisitsnumberNullable
requiresBadgebooleanWhether they demand a backlink badge
minimumPricenumber0 when free
submissionExperiencestringNullable
featuredboolean
categoriesarray[{ slug, name }]
smallDescriptionstringNullable
createdAt, updatedAtstringISO 8601

GET /directories/{slug} adds fullDescription, features, useCases, faq, deal ({ text, code } or null), frame, and socials.

Note the two url fields: url is our profile page, website is the directory itself. Direct submission form URLs (submissionLink) are not in the catalog API or MCP — they are part of the paid list product on the site and dashboard.

Picking submission targets

curl -s "https://www.aidirectori.es/api/v1/directories?cost=Free&limit=100" \
  -H "Authorization: Bearer $AID_KEY" \
  | jq -r '.data
      | map(select(.requiresBadge == false and .domainRating != null))
      | sort_by(-.domainRating)
      | .[]
      | [.domainRating, .name, .website] | @tsv'

Free, no badge required, strongest domains first.

REST API / Submit & partners

Submit & partners

API-key endpoints for submitting tools, polling status, webhooks, and support.

These are not anonymous. We issue a key per partner. MCP does not call them.

Submit a tool

POST https://www.aidirectori.es/api/v1/submit-ai-tool

Creates a listing. Send paymentType to queue directory submissions for that package. Omit it and the tool is created as waiting so the package can be set later in admin.

Required

9

Missing any of these returns 400.

FieldTypeNotes

  • name string Max 100 characters.
  • website url Public URL of the product.
  • tagline string Max 200 characters.
  • description string What the product does.
  • category string Slug or name. We map it onto an existing category.
  • pricing enum FREE PAID FREEMIUM The product’s own pricing — not the directory package.
  • founderName string You collect this before you POST.
  • founderEmail email You collect this. Never returned on public catalog reads. Do not send from a browser.
  • tags string[] Slugs or names.

Recommended

5

The request succeeds without these — we generate a slug, fetch icon/og:image, and leave the package as waiting. Send them when you have them.

FieldTypeNotes

  • paymentType enum starter pro premium Directory package: 30+, 60+, or 100+ submissions. Send this if the customer already picked a package. Omit only if you want the tool created as waiting so admin can set it later.
  • slug string Public URL slug. Generated from name (and uniqued) if omitted — send it when you already have a stable slug.
  • icon url Square logo. If omitted, we fetch the site favicon — send your own for a better listing.
  • frame url Main screenshot. If omitted, we fetch og:image — send a product shot when you have one.
  • screenshots url[] Gallery images, mirrored to Cloudflare. Not required; frame covers the hero if this is empty.

Optional

11

Images at public URLs are mirrored to Cloudflare.

FieldTypeNotes

  • video url YouTube or Vimeo.
  • socials object Keys to URLs, e.g. { "twitter": "https://x.com/…" }.
  • features object String map, e.g. { "Templates": "50+" }. Generated if omitted.
  • faq array If omitted, scraped from the site or generated.
  • affiliate string Affiliate program copy.
  • affiliateLink url
  • discountCode string Promo code shown on the listing.
  • location string Where the company is based.
  • foundingDate string Founding date, free-form.
  • isCustomer boolean Whether they are already a customer.
  • isLaunched boolean Whether the product is live.
curl -s -X POST "https://www.aidirectori.es/api/v1/submit-ai-tool" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My Tool",
    "website": "https://mytool.com",
    "tagline": "One-line pitch",
    "description": "What the product does.",
    "category": "productivity",
    "pricing": "FREE",
    "paymentType": "pro",
    "founderName": "Jane Founder",
    "founderEmail": "jane@mytool.com",
    "tags": ["ai", "productivity"],
    "icon": "https://mytool.com/icon.png",
    "frame": "https://mytool.com/screenshot.png",
    "screenshots": ["https://mytool.com/gallery-1.png"]
  }'

Poll submission status

GET https://www.aidirectori.es/api/v1/ai-tools/status — look up a tool your key submitted with exactly one of id, slug, or website. Other clients’ tools return 404.

Use this anytime — not only when a webhook fires. Poll while summary.isComplete is false, then stop (or wait for Done). submissionState is IN_QUEUE, ASSIGNED, IN_PROGRESS, REVIEW, DONE, or null when there is no directory workflow.

curl -s "https://www.aidirectori.es/api/v1/ai-tools/status?slug=my-ai-tool" \
  -H "X-API-Key: YOUR_API_KEY"

Webhook

We POST JSON to an HTTPS URL stored on your API client — not sent on each submit. Give us the URL when you apply; we store it as webhookUrl and send you a signing secret. Both directory-Done and support replies hit that same endpoint.

The directory event fires when an admin clicks Done on a tool your key submitted and webhookUrl is set. Missing URL: we send nothing. Your endpoint down or non-2xx: the tool is still marked Done. We do not retry yet — poll status if you need a fallback.

Events

2

Read X-AI-Directories-Event before you parse the body.

FieldTypeNotes

  • directory_submissions.completed Done Admin marked directory work Done for a tool your key submitted. Payload is { event, occurredAt, tool, summary, submissions }.
  • support.replied reply A support reply is ready (AI or human). Payload is { event, occurredAt, conversation }. Only if support is enabled.

Request

MethodPOST
Content-Typeapplication/json
AuthHMAC header — not your API key

Headers

3

FieldTypeNotes

  • X-AI-Directories-Event string Which payload you got. Branch on this — the same URL receives both events.
  • X-AI-Directories-Signature string sha256=<hex> HMAC of the raw body with your signing secret. Present when we issued a secret.
  • User-Agent string AI-Directories-Webhook/1.0

Verify the signature

HMAC-SHA256 over the raw request body with the secret we gave you. Compare the hex digest to X-AI-Directories-Signature after stripping the sha256= prefix. Use a timing-safe compare.

const crypto = require("crypto");

function verifySignature(rawBody, signatureHeader, secret) {
  const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  const received = String(signatureHeader || "").replace(/^sha256=/, "");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received));
}

Payload

submissions only includes directories we actually submitted. Each row can include the live listingUrl, proof screenshot, domain rating, and who submitted it (ADMIN or OWNER). Return 2xx to acknowledge.

{
  "event": "directory_submissions.completed",
  "occurredAt": "2026-09-01T13:00:00.000Z",
  "tool": {
    "id": "64a1b2c3d4e5f6789012345",
    "name": "My AI Tool",
    "slug": "my-ai-tool",
    "website": "https://myaitool.com",
    "paymentStatus": "prolist",
    "paymentLabel": "Pro · 60+",
    "targetDirectoriesCount": 60
  },
  "summary": {
    "submittedCount": 62,
    "recordedSubmissions": 62,
    "notes": "All high-DR directories completed"
  },
  "submissions": [
    {
      "name": "There's An AI For That",
      "slug": "theres-an-ai-for-that",
      "url": "https://theresanaiforthat.com",
      "listingUrl": "https://theresanaiforthat.com/ai/my-ai-tool",
      "domainRating": 81,
      "isSubmitted": true,
      "submittedBy": "ADMIN",
      "submittedAt": "2026-09-01T12:00:00.000Z"
    }
  ]
}

Customer support

Forward a question from your product UI; we answer from your knowledge base when we can, or a human replies in our dashboard. Off by default — until we enable it, POST /support/ask returns 403. Same X-API-Key as submit. MCP cannot call this.

Default mode is hybrid: AI answers when it can, otherwise the conversation stays pending for a human. We can set the client to human-only (no AI). Without product knowledge, questions wait for a person.

Send a question

POST https://www.aidirectori.es/api/v1/support/ask

Body

5

question is required. Reuse conversationId or externalId to continue a thread. Human-only clients may send metadata.peerPushMessageId for idempotent retries.

FieldTypeNotes

  • question string The customer’s question. Max 4000 characters. message is also accepted.
  • conversationId string Continue a thread we returned earlier.
  • externalId string Your ticket or thread id. Reusing it continues the same conversation.
  • customer object Optional { name, email, id } for the end customer — not the founder from submit.
  • metadata object Arbitrary JSON stored on the conversation.
curl -s -X POST "https://www.aidirectori.es/api/v1/support/ask" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "question": "How do I cancel my subscription?",
    "externalId": "ticket-123",
    "customer": { "name": "Ada", "email": "ada@example.com" }
  }'

Hybrid/AI: 200 with status: "answered" means reply is ready (replySource is ai or human). pending means poll or wait for the webhook.

{
  "success": true,
  "data": {
    "id": "64a1b2c3d4e5f6789012345",
    "status": "answered",
    "externalId": "ticket-123",
    "reply": "You can cancel from Settings → Billing.",
    "replySource": "ai",
    "messages": [
      { "role": "customer", "content": "How do I cancel my subscription?" },
      { "role": "assistant", "content": "You can cancel from Settings → Billing.", "source": "ai" }
    ]
  }
}

Human-only clients get a slim envelope — no history, customer, or messages[]. message is null until a human replies, then a single agent message.

{
  "success": true,
  "data": {
    "id": "64a1b2c3d4e5f6789012345",
    "externalId": "ticket-123",
    "status": "pending",
    "message": null
  }
}

Poll a conversation

GET https://www.aidirectori.es/api/v1/support/conversations/:id — or list with ?id=, ?externalId=, or ?status=pending. Suggested interval while pending: 5–15 seconds. Hybrid list results omit the full messages array; human-only returns the same slim shape as ask.

curl -s "https://www.aidirectori.es/api/v1/support/conversations/64a1b2c3d4e5f6789012345" \
  -H "X-API-Key: YOUR_API_KEY"

Webhook when a reply is ready

If webhookUrl is set, we POST support.replied — same HMAC as directory Done. Hybrid/AI payload uses reply / replySource. Human-only uses a singular conversation.message with role: "agent" and source: "human".

{
  "event": "support.replied",
  "occurredAt": "2026-09-09T09:01:00.000Z",
  "conversation": {
    "id": "64a1b2c3d4e5f6789012345",
    "status": "answered",
    "externalId": "ticket-123",
    "reply": "You can cancel from Settings → Billing.",
    "replySource": "human"
  }
}
{
  "event": "support.replied",
  "occurredAt": "2026-09-11T12:00:00.000Z",
  "conversation": {
    "id": "64a1b2c3d4e5f6789012345",
    "externalId": "ticket-123",
    "status": "answered",
    "message": {
      "id": "...",
      "role": "agent",
      "source": "human",
      "content": "Thanks — here's how to cancel…",
      "createdAt": "2026-09-11T12:00:00.000Z"
    }
  }
}

Email support@thedirectori.es for a key, webhook URL, signing secret, or support access — or apply from Got a directory?.

Reference / Rate limits

Rate limits

Standard keys get 10 requests per minute. Premium keys get 60. Headers on every response.

Limits are per API key, not per IP — and REST and MCP draw on separate budgets, so an agent burst cannot starve your server-side scripts.

KeyREST / minuteMCP / minute
Standard (aid_ from the dashboard)1030
Premium (paid Catalog API plan, admin grant, or issued partner key)60120

The MCP budget is the larger one because agents fan out: one question from a user routinely becomes several parallel tool calls.

The handshake is free

initialize, notifications/initialized, ping, and tools/list cost nothing. Connecting a client, or restarting one, does not spend your quota — only tools/call does. A malformed request body is not charged either.

Every response includes X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. 429 also sends Retry-After.

Upgrade from your developer dashboard ($9/month). Do not impersonate search-engine or assistant crawlers to dump the catalog.

Need a higher limit? Email support@thedirectori.es.

Partner submit/support keys have their own write limits; they use the premium catalog budget when reading.

Reference / Errors

Errors

JSON error shape and HTTP status codes.

{ "success": false, "error": "Tool not found." }
HTTPMeaning
400Bad request
401Missing or invalid API key
403Key valid but feature not enabled
404Tool, directory, or conversation not found
429Rate limit
500 / 503Server or database issue — retry

MCP uses JSON-RPC errors (-32601 method not found, -32603 internal, and tool isError payloads).