đ§ Tools
Full CRUD for AI tool listings. Creators can publish tools (requires active subscription). Visitors can browse, search, review, rate, and bookmark tools.
List Tools
âļReturns a paginated list of active AI tools with filtering, search, and sorting. Results are cached in KV for 60 seconds.
| Param | Type | Default | Description |
|---|---|---|---|
| page | number | 1 | Page number |
| limit | number | 20 | Results per page (max 200) |
| search | string | â | Search in name, description |
| toolType | string | â | e.g. general, lawyer, video, real-estate |
| pricingModel | enum | â | free | freemium | paid | enterprise |
| featured | boolean | â | Filter featured tools only |
| targetIndustry | string | â | Industry slug e.g. marketing |
| tags | string | â | Comma-separated tags |
| sortBy | enum | rank | rank | createdAt | rating | viewCount | reviewCount | name | startingPrice |
| sortOrder | enum | desc | asc | desc |
{
"success": true,
"data": {
"tools": [
{
"id": "tool_abc",
"slug": "my-ai-tool",
"name": "My AI Tool",
"singleLineDescription": "AI that does everything",
"logoUrl": "https://example.com/logo.png",
"toolType": "general",
"targetIndustries": ["marketing", "healthcare"],
"tags": ["ai", "automation"],
"pricingModel": "freemium",
"startingPrice": 19,
"status": "active",
"featured": false,
"verified": true,
"viewCount": 1250,
"rating": 4.3,
"reviewCount": 28,
"rankScore": 312.5,
"createdAt": "2026-02-01T00:00:00.000Z",
"user": { "id": "usr_abc", "username": "johndoe", "avatar": "..." }
}
],
"pagination": { "total": 480, "page": 1, "limit": 20, "totalPages": 24 }
}
}
Homepage Listing
âļ
Returns all four slot layers in a single response for the main site page.
Each layer has its own ordering logic. Use the optional type param to scope
all layers to a specific toolType â every sub-site (Lawyers, Videos, Real Estate) passes
its own type so each gets an independent, cached listing.
Results are cached in KV for 1 hour, keyed per type.
| Param | Type | Required | Description |
|---|---|---|---|
| type | string | optional |
Scope all layers to this toolType.
e.g. lawyer, video, real-estate.
Omit for the general directory (all types).
|
| Key | Max | Order | Description |
|---|---|---|---|
| featured | 12 | rankScore DESC | Admin-curated tools (featured = true). Immediate KV purge when admin toggles. |
| promoted | 5 | â | Paid promoted tools. Always [] until the promotions table is added. |
| newAndRising | 12 | rankScore DESC | Published within the last 30 days, excluding featured. Each item includes daysLive and recencyBonus (+50â+30â+15â+5 weekly step-down). |
| ranked | 24 (page 1) | rankScore DESC | All remaining active tools, excluding ids already in layers above. Use meta.rankedTotal for pagination. |
{
"success": true,
"data": {
"featured": [
{
"id": "tool_abc", "slug": "harvey-ai", "name": "Harvey AI",
"featured": true, "verified": true, "rankScore": 412.5
}
],
"promoted": [],
"newAndRising": [
{
"id": "tool_xyz", "slug": "new-tool", "name": "New Tool",
"publishedAt": "2026-04-23T00:00:00.000Z",
"daysLive": 4,
"recencyBonus": 50
}
],
"ranked": [
{ "id": "tool_def", "slug": "ranked-tool", "rankScore": 198.0 }
],
"meta": {
"type": "lawyer",
"rankedTotal": 84,
"rankedAt": "2026-04-27T06:00:00.000Z"
}
}
}
| Site | Request |
|---|---|
| General directory | GET /api/tools/homepage |
| AI for Lawyers | GET /api/tools/homepage?type=lawyer |
| AI for Videos | GET /api/tools/homepage?type=video |
| AI for Real Estate | GET /api/tools/homepage?type=real-estate |
type value gets its own independent KV cache entry â type-scoped
changes (e.g. a new lawyer tool published) do not invalidate the video or real-estate
homepage caches.
See Homepage Listing Strategy for the full slot-layer
and cache design.
Featured Tools
âļReturns top tools ranked by view count and plan tier (higher-paying creators rank higher within the same view tier). Cached for 5 minutes.
| Param | Type | Default | Description |
|---|---|---|---|
| limit | number | 10 | Number of tools to return (max 50) |
{ "success": true, "data": { "tools": [ /* tool objects */ ] } }
Get Tool by Slug
âļReturns a single tool's full details including reviews and bookmark count. Increments viewCount once per visitor per day (cookie-based dedup).
| Param | Type | Description |
|---|---|---|
| slug | string | Tool URL slug |
{
"success": true,
"data": {
"id": "tool_abc",
"slug": "my-ai-tool",
"name": "My AI Tool",
"description": "Full description...",
"websiteUrl": "https://mytool.com",
"screenshotUrls": ["https://..."],
"features": [{ "title": "Feature 1", "description": "..." }],
"useCases": ["Marketing automation"],
"pros": "Easy to use, great API",
"cons": "No mobile app",
"platform": ["Web", "API"],
"languages": ["English"],
"apiAccess": true,
"typeMetadata": {},
"reviews": [
{
"name": "John Doe",
"rating": 5,
"content": "Great tool!",
"createdAt": "2026-04-10T09:00:00.000Z"
}
],
"_count": { "bookmarks": 42 }
}
}
Published Tool Slugs
âļReturns an array of published tool slugs. Used by sub-sites to build sitemaps and pre-render pages.
| Param | Type | Default | Description |
|---|---|---|---|
| limit | number | 500 | Max slugs to return (max 500) |
| type | string | â | Filter by toolType e.g. lawyer |
{
"success": true,
"data": {
"slugs": ["my-ai-tool", "another-tool", "best-ai-tool"],
"total": 3
}
}
Check Slug Availability
âļ| Param | Type | Required | Description |
|---|---|---|---|
| slug | string | required | Slug to check (lowercase, hyphens only) |
{ "success": true, "data": { "slug": "my-tool", "available": true } }
Track Click
âļIncrements the tool's click count when a visitor clicks through to the tool's website. No auth required. Fire-and-forget â does not block the response.
{ "success": true, "message": "Click tracked." }
Authenticated Endpoints
Create Tool
đ Auth Required âļCreates a new tool listing. Requires an active subscription. The plan's max_tools setting limits how many tools a creator can publish.
| Field | Type | Required | Description |
|---|---|---|---|
| name | string | required | 2â100 characters |
| websiteUrl | string (URL) | required | Tool's website |
| toolType | string | required | e.g. general, lawyer, video, real-estate |
| pricingModel | enum | required | free | freemium | paid | enterprise |
| slug | string | optional | Auto-generated from name if omitted |
| singleLineDescription | string | optional | Max 120 chars â used in cards |
| description | string | optional | Full description, max 5000 chars |
| logoUrl | string (URL) | optional | Tool logo image URL |
| screenshotUrls | string[] | optional | Up to 10 screenshot URLs |
| targetIndustries | string[] | optional | Up to 20 industry slugs |
| tags | string[] | optional | Up to 30 tags |
| features | object[] | optional | [{ title, description }] â up to 20 |
| useCases | string[] | optional | Up to 20 use case strings |
| pros | string | optional | Max 2000 chars |
| cons | string | optional | Max 2000 chars |
| startingPrice | number | optional | Starting price in USD |
| apiAccess | boolean | optional | Does the tool have an API? |
| platform | string[] | optional | e.g. ["Web", "iOS", "API"] |
| languages | string[] | optional | Supported languages |
| typeMetadata | object | optional | Type-specific data (see Video/Lawyer/RE metadata schemas) |
| status | enum | optional | draft | active â defaults to draft |
{
"name": "ContractAI Pro",
"websiteUrl": "https://contractai.io",
"toolType": "lawyer",
"pricingModel": "paid",
"startingPrice": 49,
"singleLineDescription": "AI-powered contract review in seconds",
"targetIndustries": ["legal", "corporate"],
"tags": ["contract", "legal-ai", "review"],
"status": "active",
"typeMetadata": {
"practiceAreas": ["contract-review", "corporate"],
"functional": ["document-drafting", "contract-analysis"],
"compliance": {
"gdpr": true,
"soc2": true,
"trainsOnUserData": false
}
}
}
{
"success": true,
"message": "Tool created successfully.",
"data": { "tool": { /* full tool object */ } }
}
402 PLAN_LIMIT_EXCEEDED if the user has reached their plan's tool limit. Requires active subscription â returns 402 without one.
Update Tool
đ Auth Required âļUpdates an existing tool. All fields are optional. Only the tool owner (or an admin) can update a tool. Triggers sub-site revalidation.
| Param | Type | Description |
|---|---|---|
| id | string | Tool ID (UUID) |
Same fields as Create Tool â all optional. Omitted fields are not changed.
{ "success": true, "message": "Tool updated successfully.", "data": { "tool": { /* ... */ } } }
Delete Tool
đ Auth Required âļPermanently deletes a tool and all its reviews/bookmarks (cascade). Only the owner or an admin can delete. Triggers sub-site revalidation.
{ "success": true, "message": "Tool deleted successfully." }
Reviews & Ratings
Create Review
âļ
Submits a review for a tool. No authentication required â anyone can leave a review
by providing their name, email, a star rating, and written content. One review per email per tool.
Recalculates the tool's aggregate rating and reviewCount after creation.
| Param | Type | Description |
|---|---|---|
| id | string | Tool UUID |
| Field | Type | Required | Validation |
|---|---|---|---|
| name | string | required | 1 â 100 characters |
| string | required | Valid email address â used for dedup | |
| rating | number | required | 1 â 5 |
| content | string | required | 10 â 1000 characters |
| recaptchaToken | string | required | Token from grecaptcha.execute() (v3) or grecaptcha.getResponse() (v2). Verified server-side before saving. |
{
"success": true,
"message": "Review submitted successfully.",
"data": {
"review": {
"name": "John Doe",
"rating": 5,
"content": "Amazing tool, very intuitive!",
"createdAt": "2026-04-22T10:00:00.000Z"
}
}
}
{ "success": false, "message": "You have already reviewed this tool." }
{ "success": false, "errorCode": "TOOL_NOT_FOUND" }
List Reviews
âļ
Returns paginated reviews for a tool. Public â no auth required.
The tool detail endpoint (GET /slug/:slug) embeds the 10 most recent reviews;
use this endpoint for full pagination.
| Param | Type | Description |
|---|---|---|
| id | string | Tool UUID |
| Param | Type | Default | Description |
|---|---|---|---|
| page | number | 1 | Page number (1-based) |
| limit | number | 10 | Reviews per page (max 50) |
email field is returned only when
the caller is an authenticated admin (role = "admin").
All other callers â public or regular users â receive reviews without the email field.
{
"success": true,
"data": {
"reviews": [
{
"name": "Jane Smith",
"rating": 4,
"content": "Great for legal drafting!",
"createdAt": "2026-04-20T08:30:00.000Z"
}
],
"pagination": { "total": 28, "page": 1, "limit": 10, "totalPages": 3 }
}
}
{
"success": true,
"data": {
"reviews": [
{
"name": "Jane Smith",
"email": "janesmith@example.com",
"rating": 4,
"content": "Great for legal drafting!",
"createdAt": "2026-04-20T08:30:00.000Z"
}
],
"pagination": { "total": 28, "page": 1, "limit": 10, "totalPages": 3 }
}
}
X-Total-Count header with the total review count for convenience.
Delete Review
đĄ Admin Only âļ
Deletes a review. Admin only â reviews are submitted anonymously so there is no user
ownership to check. Recalculates the tool's aggregate rating and
reviewCount from the remaining reviews after deletion.
| Param | Type | Description |
|---|---|---|
| id | string | Tool UUID |
| reviewId | string | Review UUID |
{ "success": true, "message": "Review deleted." }
{ "success": false, "errorCode": "TOOL_NOT_FOUND" }
Rate Tool
đ Auth Required âļ
Submits a star-only rating (1â5) without a written review. Upserts â calling
again replaces the previous rating in place. After each upsert the tool's aggregate
rating is recalculated from all ToolRating rows for that tool.
POST /:id/reviews requires written content
and counts toward reviewCount. POST /:id/rate is a silent
star-only signal â it also influences the aggregate rating field but is
tracked separately in the ToolRating table.
| Param | Type | Description |
|---|---|---|
| id | string | Tool UUID |
| Field | Type | Required | Validation |
|---|---|---|---|
| rating | number | required | 1 â 5 (integer) |
{ "success": true, "data": { "rating": 4 } }
{ "success": false, "errorCode": "TOOL_NOT_FOUND" }
Engagement
Toggle Upvote
đ Auth Required âļ
Toggles an upvote on a tool. First call upvotes (increments upvoteCount);
calling again removes the upvote (decrements). Both paths trigger a rank-score recalculation.
| Param | Type | Description |
|---|---|---|
| id | string | Tool UUID |
{ "success": true, "data": { "upvoted": true } }
// or { "upvoted": false } when upvote removed
Upvote Status
đ Auth Required âļReturns whether the authenticated user has upvoted this tool, plus the tool's current total upvote count. Use this to render the upvote button in the correct state (filled/unfilled) on page load without fetching the full tool object.
| Param | Type | Description |
|---|---|---|
| id | string | Tool UUID |
{
"success": true,
"data": {
"upvoted": true,
"upvoteCount": 142
}
}
Toggle Bookmark
đ Auth Required âļToggles a bookmark on a tool. First call saves the bookmark; calling again removes it. Bookmarked tools appear in the user's saved list.
| Param | Type | Description |
|---|---|---|
| id | string | Tool UUID |
{ "success": true, "data": { "bookmarked": true } }
// or { "bookmarked": false } when removed
Admin Endpoints
Admin List All Tools
đĄ Admin Only âļReturns all tools across all statuses (draft, active, archived) with extended admin filters. No caching â always live data.
| Param | Type | Description |
|---|---|---|
| status | enum | draft | active | archived |
| verified | boolean | Filter by verification status |
| apiAccess | boolean | Filter by API access flag |
| minPrice | number | Minimum starting price |
| maxPrice | number | Maximum starting price |
Update Tool Status
đĄ Admin Only âļ| Field | Type | Required | Description |
|---|---|---|---|
| status | enum | required | draft | active | archived |
| featured | boolean | optional | Mark as featured |
| verified | boolean | optional | Mark as verified |
Bulk Import Tools
đĄ Admin Only âļImports up to 100 tools in a single request. Each tool is processed independently â failures are reported without aborting the batch. Bypasses plan limits.
| Field | Type | Required | Description |
|---|---|---|---|
| tools | object[] | required | Array of tool objects (1â100). Same schema as Create Tool. |
| publishImmediately | boolean | optional | If true, tools are set to active. Default: true |
{
"success": true,
"data": {
"summary": { "total": 5, "created": 4, "skipped": 1, "failed": 0 },
"created": [ /* tool objects */ ],
"skipped": [{ "name": "Duplicate Tool", "reason": "Duplicate name for this user" }],
"failed": []
}
}
Bulk Update Tools
đĄ Admin Only âļ| Field | Type | Required | Description |
|---|---|---|---|
| tools | object[] | required | Array of partial tool objects, each must include id (UUID) |
{
"tools": [
{ "id": "tool_abc", "featured": true, "status": "active" },
{ "id": "tool_def", "pricingModel": "freemium" }
]
}