The Index Indexes API
Approved indie web and small web index sites.
Approved indie web and small web index sites.
openapi: 3.1.0
info:
title: theindex.fyi Indexes API
version: '1.0'
description: 'A public, read-only API for theindex.fyi — a maintained meta-index of indie web
and small web index sites.
All responses follow the [JSON:API 1.1](https://jsonapi.org/) specification and use
the `application/vnd.api+json` content type.
**Rate limiting:** 60 requests per minute per IP. Responses include `X-RateLimit-Limit`,
`X-RateLimit-Remaining`, and `Retry-After` headers.
**Versioning:** The API is currently unversioned. If a breaking change is ever necessary,
versioning will be introduced via an `API-Version` request header rather than URL prefixes.
'
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:
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
ErrorDocument:
type: object
required:
- errors
properties:
errors:
type: array
minItems: 1
items:
$ref: '#/components/schemas/ErrorObject'
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".
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
responses:
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.
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".
parameters:
PageNumber:
name: page[number]
in: query
required: false
description: Page number (1-based).
schema:
type: integer
minimum: 1
default: 1
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
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
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