{ "openapi": "3.1.0", "info": { "title": "theindex.fyi", "version": "1.0", "description": "A public, read-only API for theindex.fyi \u2014 a maintained meta-index of indie web\nand small web index sites.\n\nAll responses follow the [JSON:API 1.1](https://jsonapi.org/) specification and use\nthe `application/vnd.api+json` content type.\n\n**Rate limiting:** 60 requests per minute per IP. Responses include `X-RateLimit-Limit`,\n`X-RateLimit-Remaining`, and `Retry-After` headers.\n\n**Versioning:** The API is currently unversioned. If a breaking change is ever necessary,\nversioning will be introduced via an `API-Version` request header rather than URL prefixes.\n", "contact": { "url": "https://theindex.fyi/about" } }, "servers": [ { "url": "https://theindex.fyi/api", "description": "Production" } ], "tags": [ { "name": "Indexes", "description": "Approved indie web and small web index sites." } ], "paths": { "/indexes": { "get": { "operationId": "listIndexes", "summary": "List indexes", "description": "Returns a paginated, filterable list of all active indexes.", "tags": [ "Indexes" ], "parameters": [ { "$ref": "#/components/parameters/FilterCategory" }, { "$ref": "#/components/parameters/FilterLanguage" }, { "$ref": "#/components/parameters/PageNumber" }, { "$ref": "#/components/parameters/PageSize" } ], "responses": { "200": { "description": "A paginated collection of index resources.", "content": { "application/vnd.api+json": { "schema": { "$ref": "#/components/schemas/IndexCollection" }, "example": { "data": [ { "type": "indexes", "id": "1", "attributes": { "name": "ooh.directory", "slug": "ooh-directory", "url": "https://ooh.directory", "description": "A curated directory of personal websites and blogs.", "category": "curated_directories", "language": null, "accepts_submissions": true, "last_checked_at": "2026-05-01T12:00:00Z" }, "links": { "self": "https://theindex.fyi/api/indexes/ooh-directory" } } ], "meta": { "total": 84, "per_page": 25, "current_page": 1, "last_page": 4 }, "links": { "self": "https://theindex.fyi/api/indexes?page[number]=1", "first": "https://theindex.fyi/api/indexes?page[number]=1", "last": "https://theindex.fyi/api/indexes?page[number]=4", "prev": null, "next": "https://theindex.fyi/api/indexes?page[number]=2" } } } } }, "429": { "$ref": "#/components/responses/TooManyRequests" } } } }, "/indexes/{slug}": { "get": { "operationId": "getIndex", "summary": "Get an index", "description": "Returns a single index by its slug.", "tags": [ "Indexes" ], "parameters": [ { "name": "slug", "in": "path", "required": true, "description": "The unique slug of the index.", "schema": { "type": "string" }, "example": "ooh-directory" } ], "responses": { "200": { "description": "A single index resource.", "content": { "application/vnd.api+json": { "schema": { "$ref": "#/components/schemas/IndexResource" }, "example": { "data": { "type": "indexes", "id": "1", "attributes": { "name": "ooh.directory", "slug": "ooh-directory", "url": "https://ooh.directory", "description": "A curated directory of personal websites and blogs.", "category": "curated_directories", "language": null, "accepts_submissions": true, "last_checked_at": "2026-05-01T12:00:00Z" }, "links": { "self": "https://theindex.fyi/api/indexes/ooh-directory" } } } } } }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/TooManyRequests" } } } } }, "components": { "parameters": { "FilterCategory": { "name": "filter[category]", "in": "query", "required": false, "description": "Filter indexes by category.", "schema": { "type": "string", "enum": [ "curated_directories", "rss_feed_aggregators", "search_engines", "random_discovery", "constraint_based_clubs", "indieweb_infrastructure" ] }, "example": "curated_directories" }, "FilterLanguage": { "name": "filter[language]", "in": "query", "required": false, "description": "Filter by ISO 639-1 language code. Omit to return all languages.", "schema": { "type": "string", "minLength": 2, "maxLength": 2 }, "example": "es" }, "PageNumber": { "name": "page[number]", "in": "query", "required": false, "description": "Page number (1-based).", "schema": { "type": "integer", "minimum": 1, "default": 1 } }, "PageSize": { "name": "page[size]", "in": "query", "required": false, "description": "Number of results per page. Maximum 100.", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 25 } } }, "schemas": { "IndexAttributes": { "type": "object", "required": [ "name", "slug", "url", "description", "category", "accepts_submissions" ], "properties": { "name": { "type": "string", "description": "Display name of the index.", "example": "ooh.directory" }, "slug": { "type": "string", "description": "URL-safe unique identifier.", "example": "ooh-directory" }, "url": { "type": "string", "format": "uri", "description": "The index's URL.", "example": "https://ooh.directory" }, "description": { "type": "string", "description": "One-sentence description of what the index is and who it's for.", "example": "A curated directory of personal websites and blogs." }, "category": { "type": "string", "description": "The category this index belongs to.", "enum": [ "curated_directories", "rss_feed_aggregators", "search_engines", "random_discovery", "constraint_based_clubs", "indieweb_infrastructure" ], "example": "curated_directories" }, "language": { "type": [ "string", "null" ], "description": "ISO 639-1 language code of the index's primary language. Null if English or unknown.", "example": "es" }, "accepts_submissions": { "type": "boolean", "description": "Whether this index accepts submissions from the public.", "example": true }, "last_checked_at": { "type": [ "string", "null" ], "format": "date-time", "description": "When the link was last verified as live.", "example": "2026-05-01T12:00:00Z" } } }, "IndexResourceObject": { "type": "object", "required": [ "type", "id", "attributes", "links" ], "properties": { "type": { "type": "string", "enum": [ "indexes" ] }, "id": { "type": "string", "description": "Unique numeric ID as a string, per JSON:API spec.", "example": "1" }, "attributes": { "$ref": "#/components/schemas/IndexAttributes" }, "links": { "type": "object", "required": [ "self" ], "properties": { "self": { "type": "string", "format": "uri", "example": "https://theindex.fyi/api/indexes/ooh-directory" } } } } }, "IndexResource": { "type": "object", "required": [ "data" ], "properties": { "data": { "$ref": "#/components/schemas/IndexResourceObject" } } }, "IndexCollection": { "type": "object", "required": [ "data", "meta", "links" ], "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/IndexResourceObject" } }, "meta": { "type": "object", "required": [ "total", "per_page", "current_page", "last_page" ], "properties": { "total": { "type": "integer", "description": "Total number of matching indexes across all pages.", "example": 84 }, "per_page": { "type": "integer", "example": 25 }, "current_page": { "type": "integer", "example": 1 }, "last_page": { "type": "integer", "example": 4 } } }, "links": { "type": "object", "required": [ "self", "first", "last" ], "properties": { "self": { "type": "string", "format": "uri" }, "first": { "type": "string", "format": "uri" }, "last": { "type": "string", "format": "uri" }, "prev": { "type": [ "string", "null" ], "format": "uri" }, "next": { "type": [ "string", "null" ], "format": "uri" } } } } }, "ErrorObject": { "type": "object", "required": [ "status", "title" ], "properties": { "status": { "type": "string", "description": "HTTP status code as a string.", "example": "404" }, "title": { "type": "string", "description": "Short, human-readable summary of the problem.", "example": "Not Found" }, "detail": { "type": "string", "description": "Human-readable explanation specific to this occurrence.", "example": "No index exists with the slug \"not-a-real-index\"." } } }, "ErrorDocument": { "type": "object", "required": [ "errors" ], "properties": { "errors": { "type": "array", "minItems": 1, "items": { "$ref": "#/components/schemas/ErrorObject" } } } } }, "responses": { "NotFound": { "description": "The requested resource does not exist.", "content": { "application/vnd.api+json": { "schema": { "$ref": "#/components/schemas/ErrorDocument" }, "example": { "errors": [ { "status": "404", "title": "Not Found", "detail": "No index exists with the slug \"not-a-real-index\"." } ] } } } }, "TooManyRequests": { "description": "Rate limit exceeded. Wait for the `Retry-After` period before retrying.", "headers": { "Retry-After": { "description": "Seconds until the rate limit resets.", "schema": { "type": "integer" }, "example": 42 }, "X-RateLimit-Limit": { "description": "Maximum requests allowed per minute.", "schema": { "type": "integer" }, "example": 60 }, "X-RateLimit-Remaining": { "description": "Requests remaining in the current window.", "schema": { "type": "integer" }, "example": 0 } }, "content": { "application/vnd.api+json": { "schema": { "$ref": "#/components/schemas/ErrorDocument" }, "example": { "errors": [ { "status": "429", "title": "Too Many Requests", "detail": "Rate limit of 60 requests per minute exceeded. Please slow down." } ] } } } } } } }