Quick Start
# Health check
curl https://www.adastack.io/api/v1/health
# List items (20 per page by default)
curl https://www.adastack.io/api/v1/items
# Filter by category
curl "https://www.adastack.io/api/v1/items?category=browser-wallets"
# Search
curl "https://www.adastack.io/api/v1/items?search=staking"
# Single item
curl https://www.adastack.io/api/v1/items/eternl-browser-wallet
# Get all filter options
curl https://www.adastack.io/api/v1/taxonomies
# Directory snapshot for context loading
curl https://www.adastack.io/api/v1/directoryThe API is public, read-only, and requires no API key. The base URL is https://www.adastack.io/api/v1. GET /api/v1/directory returns markdown by default.
Endpoints
GET /api/v1/items
List directory items with filtering, search, and pagination.
Example Request
curl "https://www.adastack.io/api/v1/items?category=browser-wallets&limit=1"Response 200 OK
{
"items": [
{
"name": "Eternl Browser Wallet",
"slug": "eternl-browser-wallet",
"createdAt": "2024-06-15T08:00:00.000Z",
"category": {
"name": "Browser Wallets",
"slug": "browser-wallets",
"adastackURL": "https://www.adastack.io/category/browser-wallets"
},
"section": {
"name": "Wallets",
"slug": "wallets",
"adastackURL": "https://www.adastack.io/section/wallets"
},
"miniDescription": "Feature-rich Cardano light wallet",
"description": "Full description text omitted from this example.",
"introduction": "Brief intro paragraph omitted from this example.",
"websiteURL": "https://eternl.io",
"blogURL": null,
"xURL": "https://x.com/eternaborado",
"discordURL": "https://discord.gg/eternl",
"telegramURL": null,
"linkedinURL": null,
"facebookURL": null,
"youtubeURL": null,
"subredditURL": null,
"docsURL": null,
"roadmapURL": null,
"governanceURL": null,
"careersURL": null,
"merchURL": null,
"whitepaperURL": null,
"teamGithubURL": null,
"projectGithubURL": null,
"apiDocsURL": null,
"llmsTxtURL": null,
"repoPrimaryLang": null,
"siteLanguage": null,
"collections": [],
"trackedEcosystemChains": ["cardano"],
"partnerChains": ["cardano"],
"iconURL": "https://cdn.sanity.io/images/project/dataset/icon.png?w=200&h=200&fit=max&auto=format",
"imageURL": "https://cdn.sanity.io/images/project/dataset/image.png?w=1920&h=1080&fit=max&auto=format",
"adastackURL": "https://www.adastack.io/item/eternl-browser-wallet"
}
],
"metadata": {
"total": 127,
"page": 1,
"limit": 1,
"totalPages": 127,
"hasMore": true,
"firstPage": "https://www.adastack.io/api/v1/items?limit=1&category=browser-wallets&page=1",
"lastPage": "https://www.adastack.io/api/v1/items?limit=1&category=browser-wallets&page=127",
"nextPage": "https://www.adastack.io/api/v1/items?limit=1&category=browser-wallets&page=2",
"previousPage": null,
"sort": {
"field": "name",
"order": "asc"
},
"filters": {
"category": "browser-wallets",
"chain": "cardano"
},
"generated": "2025-01-15T12:00:00.000Z"
}
}Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number (1-10,000) |
limit | integer | 20 | Items per page (1-100) |
sort | string | name | Sort field: name, updatedAt, or createdAt |
order | string | - | asc or desc (default: asc for name, desc for date sorts) |
category | string | - | Filter by category slug |
section | string | - | Filter by section/group slug |
siteLanguage | string | - | Filter by site language slug |
programmingLanguage | string | - | Filter by programming language slug |
collection | string | - | Filter by collection slug |
search | string | - | Search name and description (2-100 chars) |
chain | string | host | Filter by tracked ecosystem chain: cardano, midnight. See Chain filtering. |
Fields
Each object in items contains:
| Field | Type | Description |
|---|---|---|
name | string | Display name (always present) |
slug | string | URL-safe identifier (always present) |
createdAt | string | ISO-8601 timestamp of initial creation |
category | object | null | Parent category {name, slug, adastackURL} |
section | object | null | Parent section {name, slug, adastackURL} |
miniDescription | string | null | One-liner description |
description | string | null | Full description |
introduction | string | null | Intro paragraph |
websiteURL | string | null | Main website |
blogURL | string | null | Blog or news feed |
xURL | string | null | X (Twitter) profile |
discordURL | string | null | Discord invite |
telegramURL | string | null | Telegram group/channel |
linkedinURL | string | null | LinkedIn page |
facebookURL | string | null | Facebook page |
youtubeURL | string | null | YouTube channel |
subredditURL | string | null | Subreddit |
docsURL | string | null | Documentation site |
roadmapURL | string | null | Public roadmap |
governanceURL | string | null | Governance portal or forum |
careersURL | string | null | Careers or jobs page |
merchURL | string | null | Merchandise store |
whitepaperURL | string | null | Whitepaper or technical documentation |
teamGithubURL | string | null | GitHub organization or team page |
projectGithubURL | string | null | GitHub project repository |
apiDocsURL | string | null | API reference documentation |
llmsTxtURL | string | null | llms.txt manifest for AI agents |
repoPrimaryLang | object | null | Primary programming language {name, slug, miniDescription, adastackURL} |
siteLanguage | object | null | Site content language {name, slug, miniDescription, adastackURL} |
collections | array | Curated collections [{name, slug, miniDescription, adastackURL}] (may be empty) |
trackedEcosystemChains | string[] | Tracked ecosystem chains the item is classified under (e.g. ["cardano"], ["cardano","midnight"]); empty array for untagged Cardano-default items |
partnerChains | string[] | Deprecated v1 alias for trackedEcosystemChains; identical values, scheduled for removal in Developer API v2 |
iconURL | string | null | Square logo (200x200, auto-optimized) |
imageURL | string | null | Hero image (1920x1080, auto-optimized) |
adastackURL | string | Item page URL (always present) |
Metadata Fields
| Field | Type | Description |
|---|---|---|
total | integer | Total items matching filters |
page | integer | Current page number |
limit | integer | Items per page |
totalPages | integer | Total pages available |
hasMore | boolean | Whether more pages exist |
firstPage | string | null | URL for first page, or null when no results |
lastPage | string | null | URL for last page, or null when no results |
nextPage | string | null | URL for next page, or null on last page |
previousPage | string | null | URL for previous page, or null on first page |
sort | object | Applied sort {field, order} |
filters | object | Applied filters, including the effective chain and any requested taxonomy or search filters |
generated | string | ISO 8601 timestamp |
Notes
| Concept | Notes |
|---|---|
| Pagination | Pages start at 1; limit accepts 1 through 100. Responses include total, totalPages, hasMore, and absolute pagination URLs when pages exist. Requesting a page beyond totalPages returns 200 OK with an empty items array. |
| Taxonomy filters | Filter values are URL-safe slugs such as browser-wallets or dapps. Multiple filters combine with AND logic. Use GET /api/v1/taxonomies to discover valid slugs. |
| Search | search matches item name, mini description, and full description. Matching is case-insensitive and contains-based, not fuzzy or prefix-only. URL-encode spaces as %20 or +. |
| Search precision | search=lace matches "Lace wallet" and "marketplace"; search=swap matches "SundaeSwap", "Minswap", and "swap tokens". Combine search with taxonomy filters for more precise results, such as ?search=lace&category=browser-wallets. |
| Sorting | Supports sort=name, sort=updatedAt, and sort=createdAt. Default order is ascending for name and descending for date sorts unless order=asc or order=desc is provided. |
| Chain | The response always echoes the effective chain at metadata.filters.chain, including the default host chain when chain is omitted. |
GET /api/v1/items/[slug]
Get a single directory item by slug.
Example Request
curl https://www.adastack.io/api/v1/items/eternl-browser-walletResponse 200 OK
{
"item": {
"name": "Eternl Browser Wallet",
"slug": "eternl-browser-wallet",
"createdAt": "2024-06-15T08:00:00.000Z",
"category": {
"name": "Browser Wallets",
"slug": "browser-wallets",
"adastackURL": "https://www.adastack.io/category/browser-wallets"
},
"section": {
"name": "Wallets",
"slug": "wallets",
"adastackURL": "https://www.adastack.io/section/wallets"
},
"miniDescription": "Feature-rich Cardano light wallet",
"description": "Full description text omitted from this example.",
"introduction": "Brief intro paragraph omitted from this example.",
"websiteURL": "https://eternl.io",
"blogURL": null,
"xURL": "https://x.com/eternaborado",
"discordURL": "https://discord.gg/eternl",
"telegramURL": null,
"linkedinURL": null,
"facebookURL": null,
"youtubeURL": null,
"subredditURL": null,
"docsURL": null,
"roadmapURL": null,
"governanceURL": null,
"careersURL": null,
"merchURL": null,
"whitepaperURL": null,
"teamGithubURL": null,
"projectGithubURL": null,
"apiDocsURL": null,
"llmsTxtURL": null,
"repoPrimaryLang": null,
"siteLanguage": null,
"collections": [],
"trackedEcosystemChains": ["cardano"],
"partnerChains": ["cardano"],
"iconURL": "https://cdn.sanity.io/images/project/dataset/icon.png?w=200&h=200&fit=max&auto=format",
"imageURL": "https://cdn.sanity.io/images/project/dataset/image.png?w=1920&h=1080&fit=max&auto=format",
"adastackURL": "https://www.adastack.io/item/eternl-browser-wallet"
},
"metadata": {
"generated": "2025-01-15T12:00:00.000Z"
}
}Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
chain | string | host | Restrict lookup to a single chain. See Chain filtering. |
Fields
| Field | Type | Description |
|---|---|---|
item | object | Directory item. Uses the same item object shape as entries returned by GET /api/v1/items. |
metadata | object | Response metadata. |
Metadata Fields
| Field | Type | Description |
|---|---|---|
generated | string | ISO 8601 timestamp |
Notes
Returns 404 if the slug does not match any item. If the slug exists on the directory but is not tagged for the requested chain, the response is 404 with error.code: "chain_mismatch". Non-production responses include error.details.availableChains; production responses keep error details minimal and link to documentation. A genuinely missing slug returns the standard error.code: "not_found".
GET /api/v1/taxonomies
All taxonomy and reference data. Use this to discover valid slugs for filtering /api/v1/items.
Example Request
curl "https://www.adastack.io/api/v1/taxonomies?chain=cardano"Response 200 OK
{
"sections": [
{
"name": "DApps",
"slug": "dapps",
"miniDescription": "Decentralized applications on Cardano",
"description": "Decentralized applications built on Cardano",
"updatedAt": "2025-01-10T08:00:00.000Z",
"itemCount": 204,
"adastackURL": "https://www.adastack.io/section/dapps"
}
],
"categories": [
{
"name": "Browser Wallets",
"slug": "browser-wallets",
"miniDescription": "Browser extension wallets",
"description": "Browser extension wallets for Cardano",
"updatedAt": "2025-01-12T09:30:00.000Z",
"section": {
"name": "Wallets",
"slug": "wallets",
"adastackURL": "https://www.adastack.io/section/wallets"
},
"itemCount": 9,
"adastackURL": "https://www.adastack.io/category/browser-wallets"
}
],
"languages": [
{
"name": "French",
"slug": "french",
"miniDescription": "French language resources",
"description": "Items available in French",
"updatedAt": "2025-01-08T14:20:00.000Z",
"itemCount": 10,
"adastackURL": "https://www.adastack.io/languages/french"
}
],
"programmingLanguages": [
{
"name": "Haskell",
"slug": "haskell",
"miniDescription": "Haskell programming language",
"description": "Functional programming language used for Cardano development",
"updatedAt": "2025-01-08T14:20:00.000Z",
"itemCount": 15,
"adastackURL": "https://www.adastack.io/programming-languages/haskell"
}
],
"collections": [
{
"name": "DAO-Governed",
"slug": "dao-governed",
"miniDescription": "Projects directed by community votes.",
"description": "Explore Cardano's DAO-run projects—transparent, collaborative, putting power in the hands of the community.",
"updatedAt": "2025-09-21T04:59:30.000Z",
"itemCount": 20,
"adastackURL": "https://www.adastack.io/collections/dao-governed"
}
],
"metadata": {
"totalSections": 14,
"totalCategories": 106,
"totalLanguages": 26,
"totalProgrammingLanguages": 18,
"totalCollections": 2,
"sort": {
"field": "name",
"order": "asc"
},
"chain": "cardano",
"generated": "2025-01-15T12:00:00.000Z"
}
}Additional taxonomy entries are omitted from this example.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
sort | string | alphabetical | alphabetical (name asc) or curated (priority order matching website) |
chain | string | host | Filter taxonomy itemCount to a single chain. See Chain filtering. |
Fields
| Field | Type | Description |
|---|---|---|
sections | array | Section taxonomy objects |
categories | array | Category taxonomy objects; each includes a parent section object |
languages | array | Site language taxonomy objects |
programmingLanguages | array | Programming language taxonomy objects |
collections | array | Curated collection objects |
metadata | object | Response metadata |
Taxonomy objects include name, slug, miniDescription, description, updatedAt, itemCount, and adastackURL. Categories also include a section parent object. Collections share the same shape as sections.
Metadata Fields
| Field | Type | Description |
|---|---|---|
totalSections | integer | Total section objects returned |
totalCategories | integer | Total category objects returned |
totalLanguages | integer | Total language objects returned |
totalProgrammingLanguages | integer | Total programming language objects returned |
totalCollections | integer | Total collection objects returned |
sort | object | Applied sort. Uses {field: "name", order: "asc"} for alphabetical and {field: "curated", order: "desc"} for curated. |
chain | string | Applied ecosystem chain |
generated | string | ISO 8601 timestamp |
Notes
chain reduces every taxonomy itemCount to the selected ecosystem chain. The response echoes the applied chain at metadata.chain.
GET /api/v1/directory
LLM-optimized markdown snapshot of the directory. This endpoint is intended for agents, crawlers, and context-loading workflows that benefit from a compact text representation.
Example Request
curl https://www.adastack.io/api/v1/directoryResponse 200 OK
Returns text/markdown; charset=utf-8.
# Adastack.io Site Structure Reference
## [Getting Started](https://www.adastack.io/section/getting-started) - Essential guides for blockchain beginners.
### [Cardano Guides](https://www.adastack.io/category/cardano-guides) - Guides to get started.
- [Cardano Reddit Wiki](https://www.adastack.io/item/cardano-reddit-wiki) - Cardano wiki and starter guide.
- [Cardano.org](https://www.adastack.io/item/cardano-org) - Top proof-of-stake blockchain.
- [Cardano.org Documentation](https://www.adastack.io/item/cardano-documentation) - Official Cardano documentation.
- [Developer Portal](https://www.adastack.io/item/developer-portal) - Dev guides and resources.
- [Essential Cardano Guide](https://www.adastack.io/item/essential-cardano-guide) - Links for Cardano newcomers.
### [Why Cardano](https://www.adastack.io/category/why-cardano) - Secure, Scalable, Sustainable.
- [Cardano Academy](https://www.adastack.io/item/cardano-academy) - Learn Cardano in under 10 hours.
- [Cardano Constitution](https://www.adastack.io/item/cardano-constitution) - Democratic on-chain process.
## [Wallets](https://www.adastack.io/section/wallets) - Hold and use digital assets.
### [Mobile Wallets](https://www.adastack.io/category/mobile-wallets) - Wallets for your phone.
- [Begin Mobile Wallet](https://www.adastack.io/item/begin-mobile-wallet) - Cardano crypto wallet.
- [Eternl Mobile Wallet](https://www.adastack.io/item/eternl-mobile-wallet) - Advanced Cardano light wallet interface.
<!-- additional sections, categories, and items omitted for brevity -->Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
chain | string | host | Filter the markdown directory snapshot to a single chain. See Chain filtering. |
Fields
The markdown response is organized for fast context loading:
| Markdown element | Description |
|---|---|
| H1 | Directory title |
| H2 | Section link and section mini description |
| H3 | Category link and category mini description |
| List item | Item link and item mini description |
Notes
Use this markdown response when a client or agent needs compact text for context loading. Use GET /api/v1/directory/json when a client needs ETag support or object-shaped data.
GET /api/v1/directory/json
Structured JSON snapshot of the directory. Use this endpoint when a client needs object-shaped data, jq processing, ETag support, or response metadata.
Example Request
curl "https://www.adastack.io/api/v1/directory/json?chain=cardano"Response 200 OK
{
"sections": [
{
"name": "Wallets",
"slug": "wallets",
"miniDescription": "Wallets and account tools",
"adastackURL": "https://www.adastack.io/section/wallets",
"categories": [
{
"name": "Browser Wallets",
"slug": "browser-wallets",
"miniDescription": "Browser extension wallets",
"adastackURL": "https://www.adastack.io/category/browser-wallets",
"items": [
{
"name": "Eternl Browser Wallet",
"slug": "eternl-browser-wallet",
"miniDescription": "Feature-rich Cardano light wallet",
"adastackURL": "https://www.adastack.io/item/eternl-browser-wallet",
"websiteURL": "https://eternl.io"
}
]
}
]
}
],
"metadata": {
"generated": "2025-01-15T12:00:00.000Z",
"totalSections": 14,
"totalCategories": 106,
"totalItems": 1200,
"version": "v1",
"chain": "cardano"
}
}The response returns application/json.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
chain | string | host | Filter the directory snapshot to a single chain. See Chain filtering. |
Fields
| Field | Type | Description |
|---|---|---|
sections | array | Section objects |
metadata | object | Response metadata |
Section objects include name, slug, miniDescription, adastackURL, and categories. Category objects include name, slug, miniDescription, adastackURL, and items. Item objects include name, slug, miniDescription, adastackURL, and websiteURL when available.
Metadata Fields
| Field | Type | Description |
|---|---|---|
generated | string | ISO 8601 timestamp |
totalSections | integer | Total sections in the export |
totalCategories | integer | Total categories in the export |
totalItems | integer | Total items in the export |
version | string | API version |
chain | string | Applied ecosystem chain |
Notes
The structured JSON endpoint accepts the same chain values as /api/v1/directory and echoes the applied chain at metadata.chain. It remains active but is intentionally omitted from health endpoint discovery so /api/v1/directory stays the primary advertised directory export.
GET /api/v1/directory/map
Taxonomy-only view of the directory: sections and categories with no items. Markdown by default; structured JSON via GET /api/v1/directory/map/json. Use this when you only need the directory's shape (e.g. for navigation builders, sitemaps, or tooling that classifies items into the live taxonomy) and don't want the item payload from /api/v1/directory.
curl https://www.adastack.io/api/v1/directory/map
curl "https://www.adastack.io/api/v1/directory/map/json?chain=midnight"Accepts the same chain query parameter as /api/v1/directory. Includes empty categories (those without items yet), unlike /api/v1/directory. Omitted from health endpoint discovery for the same reason as /api/v1/directory/json — /api/v1/directory remains the primary advertised export.
GET /api/v1/health
API status and endpoint discovery. Rate limit: 5,000 req/min. No caching.
Example Request
curl https://www.adastack.io/api/v1/healthResponse 200 OK
{
"status": "ok",
"statsStatus": "ok",
"version": "v1",
"timestamp": "2025-01-15T12:00:00.000Z",
"stats": {
"totalItems": 1200,
"totalCategories": 108,
"totalSections": 15
},
"rateLimit": {
"dataEndpoints": {
"requestsPerMinute": 100
},
"healthEndpoint": {
"requestsPerMinute": 5000
},
"policy": "per-ip"
},
"endpoints": [
"https://www.adastack.io/api/v1/items",
"https://www.adastack.io/api/v1/items/[slug]",
"https://www.adastack.io/api/v1/taxonomies",
"https://www.adastack.io/api/v1/directory",
"https://www.adastack.io/api/v1/health"
],
"documentation": "https://www.adastack.io/developers/api/v1"
}Query Parameters
None.
Fields
| Field | Type | Description |
|---|---|---|
status | string | Always "ok" if the API is responding |
statsStatus | string | "ok" if stats loaded, "unavailable" if CMS query failed |
version | string | API version |
timestamp | string | ISO 8601 response timestamp |
stats | object | null | Directory statistics (null when statsStatus is "unavailable") |
rateLimit | object | Rate-limit policy for data and health endpoints |
endpoints | array | Available endpoint URLs |
documentation | string | Developer documentation URL |
Notes
The stats object may be null when the CMS is temporarily unavailable. The health endpoint remains functional even when stats cannot be fetched -- check statsStatus to determine if stats are current.
GET /api and /api/v1
Discovery aliases for API clients. Both endpoints return the same discovery JSON as GET /api/v1/health and follow the same no-store caching behavior.
Example Request
curl https://www.adastack.io/apiResponse 200 OK
{
"status": "ok",
"statsStatus": "ok",
"version": "v1",
"timestamp": "2025-01-15T12:00:00.000Z",
"stats": {
"totalItems": 1200,
"totalCategories": 108,
"totalSections": 15
},
"rateLimit": {
"dataEndpoints": {
"requestsPerMinute": 100
},
"healthEndpoint": {
"requestsPerMinute": 5000
},
"policy": "per-ip"
},
"endpoints": [
"https://www.adastack.io/api/v1/items",
"https://www.adastack.io/api/v1/items/[slug]",
"https://www.adastack.io/api/v1/taxonomies",
"https://www.adastack.io/api/v1/directory",
"https://www.adastack.io/api/v1/health"
],
"documentation": "https://www.adastack.io/developers/api/v1"
}Query Parameters
None.
Fields
Same health fields as GET /api/v1/health.
Notes
GET /api/v1 is also available and returns the same response as GET /api.
Operational Reference
HTTP Methods
REST API v1 read endpoints support GET, HEAD, and OPTIONS. HEAD returns the same headers as GET with an empty body. OPTIONS returns CORS preflight headers. Write methods on known read-only endpoints return 405 method_not_allowed with an Allow: GET, HEAD, OPTIONS header.
Chain Filtering
Use ?chain= to filter endpoints that expose or count directory content. Supported values are cardano and midnight. v1 accepts a single value; multi-chain and CSV queries are not supported, so issue separate requests per chain.
When omitted, chain defaults to the host's chain (cardano on adastack.io). Items without trackedEcosystemChains tags default to Cardano for backward compatibility. Non-default chain requests return matching classified items when present.
Rate Limiting
Rate limits are per IP over a rolling 60-second window.
| Endpoint group | Limit |
|---|---|
| Data endpoints | 100 requests/minute |
| Health/discovery endpoints | 5,000 requests/minute |
GET/HEAD data and discovery responses, plus rate-limit errors, include standard rate-limit headers and legacy X-RateLimit-* headers for backward compatibility. OPTIONS preflights and 405 method_not_allowed responses focus on the method/CORS contract. For 304 Not Modified, rely on the status code, empty body, and cache validators such as ETag/Cache-Control; production edge caches may omit custom CORS, API-version, security, and rate-limit headers on 304 responses.
| Header | Example | Description |
|---|---|---|
RateLimit | limit=100, remaining=95, reset=45 | Current limit, remaining requests, seconds until reset |
RateLimit-Policy | 100;w=60 | Limit and window size (60 seconds) |
X-RateLimit-Limit | 100 | Max requests per window |
X-RateLimit-Remaining | 95 | Requests remaining in current window |
X-RateLimit-Reset | 1704067200 | Unix timestamp when the limit resets |
When rate limited, you receive 429 Too Many Requests with a Retry-After header and retryAfter in the response body. Rate limiting is applied before endpoint-specific query validation, so an over-limit request can return 429 even if its query parameters would otherwise return 400 invalid_query. Implement exponential backoff and respect the Retry-After value.
Caching
Data endpoints are cached at the edge. Cache durations vary by endpoint based on update frequency:
| Endpoint | Cache-Control | ETag |
|---|---|---|
/items, /items/[slug] | public, max-age=3600, s-maxage=3600, stale-while-revalidate=7200, stale-if-error=86400 | No |
/directory | public, max-age=3600, s-maxage=3600, stale-while-revalidate=7200, stale-if-error=86400 | Markdown: no; JSON variant: yes |
/directory/map | public, max-age=3600, s-maxage=3600, stale-while-revalidate=7200, stale-if-error=86400 | Markdown: no; JSON variant: yes |
/taxonomies | public, max-age=86400, s-maxage=86400, stale-while-revalidate=7200, stale-if-error=86400 | Yes |
/health | no-store | No |
New content may take up to 1 hour to appear in most API responses, or up to 24 hours for taxonomies.
Conditional Requests (ETag)
/api/v1/taxonomies and /api/v1/directory/json support conditional requests. Store the ETag from a 200 OK or HEAD response, then send that value as If-None-Match to receive 304 Not Modified when the data has not changed.
# First request - get the ETag from response headers
curl -i https://www.adastack.io/api/v1/taxonomies
# Response includes: ETag: "taxonomy-etag"
# Subsequent request - send ETag as If-None-Match
curl -i -H 'If-None-Match: "taxonomy-etag"' https://www.adastack.io/api/v1/taxonomies
# Returns 304 Not Modified with no body if data is unchangedCORS headers on standard responses let browsers read the ETag header and send If-None-Match in cross-origin requests. Treat 304 as a compact cache signal: production edge caches may return only the portable cache headers, so do not depend on custom response headers being present on 304.
Error Handling
All errors return a consistent JSON structure:
{
"error": {
"code": "error_code",
"message": "Human-readable description",
"details": {
"documentation": "/developers/api/v1"
}
}
}Use error.code and error.message inside the top-level error object for programmatic handling. error.details is optional diagnostic context: production responses keep it minimal, while development responses may include route-specific validation arrays such as issues or errors.
Error Codes
| Code | HTTP | Description | Resolution |
|---|---|---|---|
invalid_query | 400 | Invalid query parameters | Check parameter types and ranges |
invalid_slug | 400 | Malformed slug format | Use lowercase alphanumeric with hyphens |
not_found | 404 | Resource doesn't exist | Verify slug spelling |
chain_mismatch | 404 | Slug exists but not on requested chain | Verify the requested chain; non-production details include available chains |
method_not_allowed | 405 | HTTP method is not supported on this read-only endpoint | Use GET, HEAD, or OPTIONS |
unknown_category | 422 | Category slug not found | Use /api/v1/taxonomies for valid slugs |
unknown_section | 422 | Section slug not found | Use /api/v1/taxonomies for valid slugs |
unknown_language | 422 | Language slug not found | Use /api/v1/taxonomies for valid slugs |
unknown_programming_language | 422 | Programming language slug not found | Use /api/v1/taxonomies for valid slugs |
unknown_collection | 422 | Collection slug not found | Use /api/v1/taxonomies for valid slugs |
rate_limit_exceeded | 429 | Too many requests | Wait for Retry-After header value |
query_failed | 500 | Database query failed | Retry; contact support if persistent |
internal_error | 500 | Server error | Retry; contact support if persistent |
Technical Reference
CORS
All origins are allowed (public read-only API). Standard non-304 responses include browser-readable CORS headers:
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: ETag, RateLimit, RateLimit-Policy, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-ResetCORS preflight and 405 method_not_allowed responses advertise the read-only method contract:
Access-Control-Allow-Methods: GET, HEAD, OPTIONS
Access-Control-Allow-Headers: Content-Type, If-None-MatchSecurity Headers
Standard non-preflight responses include security headers:
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Content-Security-Policy: default-src 'none'; frame-ancestors 'none'
X-API-Version: v1Response Format
JSON endpoints return Content-Type: application/json. The LLM-optimized /api/v1/directory endpoint returns Content-Type: text/markdown; its optional structured variant returns JSON.
Response adastackURL fields use the canonical https://www.adastack.io domain.
Changelog
June 12, 2026
Item Responses:
- Added 8 key resource link fields to
/api/v1/itemsand/api/v1/items/[slug]responses:subredditURL,docsURL,roadmapURL,governanceURL,careersURL,merchURL,apiDocsURL,llmsTxtURL. Each isstring | null. Additive change; existing clients are unaffected.
Expand to see all changes
May 12, 2026
Documentation and discovery:
- Reframed
/api/v1/directoryas the primary LLM-friendly directory export. - Added
?chain=support to the markdown/api/v1/directoryresponse. - Removed
/api/v1/directory/jsonfrom health discovery while keeping it available for JSON, ETag, and metadata workflows. SortMetadata.field(response metadata type) now includes"url"in its union. Additive; clients doing exhaustive switch/match on this field should add a"url"case.
May 10, 2026
Contract alignment:
- Reordered item, taxonomy, directory, and health/discovery response examples and tests to match the public documentation order.
- Documented
/apiand/api/v1discovery aliases. - Aligned
/api/v1write methods with the read-only API contract:POST,PUT,PATCH, andDELETEnow return405 method_not_allowed. - Removed internal link extraction routes from public discovery and public REST v1 documentation; use item responses for public link fields.
- Added
metadata.chainto the taxonomy example.
May 7, 2026
Contract alignment:
- Restored item response contract from v1.0.8:
updatedAtis not exposed on/itemsor/items/[slug], whilesort=updatedAtremains supported. - Added
method_not_allowederror reason and explicitAllowheaders for read-only API endpoints. - Clarified production cache headers and ETag support:
/taxonomiesand/directory/jsonsupport conditional requests; Vercel may simplify stale cache directives in production responses. - Renamed the durable item classification field to
trackedEcosystemChains.partnerChainsremains in v1 responses as a deprecated alias with identical values and is scheduled for removal in Developer API v2.
May 5, 2026
Chain filter:
- Added
?chain=query parameter on/api/v1/items,/api/v1/items/[slug],/api/v1/taxonomies, and/api/v1/directory/json. Supported values:cardano,midnight. See Chain filtering. - BREAKING: Default behavior on adastack.io is now Cardano-filtered (closes prior cross-chain leak where
/itemsreturned all items regardless of chain classification). Pre-2026-05-05 callers receive ~Cardano subset by default; pass?chain=midnightto query the Midnight subset. - Items expose chain classification on every response.
- New
chain_mismatch(404) error reason.
February 5, 2026
Item Responses:
- BREAKING: Removed
updatedAtfield from item responses (internal CMS metadata not appropriate for public API; sorting byupdatedAtstill works)
February 5, 2026
Data Quality:
- All string fields (names, descriptions) are now defensively trimmed to remove leading/trailing whitespace from CMS data
Documentation:
- Added
statsStatusfield and nullablestatsbehavior to health endpoint documentation - Added IETF rate-limit headers (
RateLimit,RateLimit-Policy) to rate limiting section - Added ETag conditional request examples
- Clarified search behavior: contains matching means "lace" also matches "marketplace" and "placeholder"
- Added note about
totalItemsdiscrepancy between/directoryand/itemsendpoints (directory only includes categorized items)
February 5, 2026
Directory Endpoint:
- BREAKING: Renamed
linktowebsiteURLin directory item objects for consistency with the items endpoint
Validation:
- Fixed pagination accepting fractional page numbers (e.g.,
?page=1.5) -- now requires integers
CORS:
- Added
If-None-MatchtoAccess-Control-Allow-Headersacross all endpoints, enabling browser-based conditional requests - Added
Access-Control-Expose-Headers: ETagto directory and taxonomies responses, allowing browsers to read ETag values
Health Endpoint:
- Added structured request logging consistent with all other endpoints
Documentation:
- Fixed search description from "prefix matching" to "contains matching"
- Fixed search minimum from "3-100 chars" to "2-100 chars"
- Added
createdAtto sort options and item fields table - Added
firstPageandlastPageto metadata fields table and all example responses - Fixed pagination URLs in examples to show absolute URLs (matching actual API behavior)
- Fixed taxonomy sort metadata from
"priority"to"curated"in documentation - Added conditional requests (ETag) section to caching documentation
February 4, 2026
Directory Endpoint:
- BREAKING: Renamed
groupstosectionsin JSON response andtotalGroupstototalSectionsin metadata, for consistency with the rest of the API
Sort Metadata (all endpoints):
- BREAKING: Taxonomies endpoint
sortchanged from string ("alphabetical") to object ({field: "name", order: "asc"}) matching items endpoint format
February 4, 2026
Health Endpoint:
rateLimitfield restructured to show both data endpoint (100 req/min) and health endpoint (5,000 req/min) limits separately
Single Item Endpoint:
- Added
metadatafield withgeneratedtimestamp toGET /api/v1/items/[slug]response for consistency with other endpoints
Items Endpoint:
metadata.filtersnow always present and includes the effectivechain
Error Codes:
- Renamed
unknown_codeerror code tounknown_programming_languagefor clarity
Documentation:
- Corrected search description from "substring matching" to "prefix matching"
- Updated versioning statement to reflect early API history
- Sanitized internal error messages in directory endpoint
Taxonomy Counts:
- Aligned taxonomy
itemCountfilters with full item filter (added slug pattern, name pattern, and publishDate checks)
February 4, 2026
Pagination:
- Added
nextPageandpreviousPageURL strings to items metadata (null when not applicable)
Bug Fixes:
- Fixed taxonomy validation error responses returning malformed
{"0": {...}}instead of{errors: [...]}
December 26, 2025
Item Response Schema:
- BREAKING: Removed
tags[]array from item responses - Added
siteLanguagefield - single object with name, slug, miniDescription, adastackURL (or null) - Added
repoPrimaryLangfield - single object with name, slug, miniDescription, adastackURL (or null)
Filter Parameters:
- BREAKING: Removed
?tag=filter parameter - Added
?siteLanguage=parameter - filter by site language slug - Added
?programmingLanguage=parameter - filter by programming language slug
Taxonomies Endpoint:
- BREAKING: Replaced
tags[]withlanguages[]andprogrammingLanguages[]arrays - BREAKING: Replaced
totalTagswithtotalLanguagesandtotalProgrammingLanguagesin metadata
January 20, 2025
- BREAKING: Renamed
iconUrltoiconURL,imageUrltoimageURL - Added server-side image transform parameters
January 15, 2025
- Initial release with
/items,/items/[slug],/taxonomiesendpoints - Rate limiting (100 req/min), caching (1hr fresh, 2hr SWR), public CORS access
Versioning: Early v1 releases (v1.0.1, v1.0.2) included breaking changes as the API stabilized. Going forward, breaking changes will ship in new API versions (v2, v3). v1 is now stable.
Support: Email contact@adastack.io to report issues, request features, or discuss rate limit increases.