---
title: Organize and annotate your API docs
description: Learn how to group Elastic APIs with tags and annotate them with lifecycle status, permissions, and version information.
url: https://www.elastic.co/docs/contribute-docs/api-docs/organize-annotate
applies_to:
  - Elastic Cloud Serverless: Generally available
  - Elastic Stack: Generally available
---

# Organize and annotate your API docs
This page explains how to organize your API documentation and add technical metadata to help users understand your APIs. You'll find guidance on:
- Adding required OpenAPI document information
- Adding structure with operation IDs and tags
- Documenting API availability and lifecycle status
- Specifying required permissions and privileges
- Extending OpenAPI with custom properties

For guidance on writing effective API content like summaries, descriptions, and examples, see [Core guidelines](https://www.elastic.co/docs/contribute-docs/api-docs/guidelines).

## Add OpenAPI document info

The published OpenAPI documents must have the following metadata in the [`info` object](https://spec.openapis.org/oas/latest#info-object):

| **Field**        | **Description**                                                                                                                                                                                                                                                                                                                                   |
|------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `description`    | A descriptive overview of the API's purpose and functionality. This should be a concise summary that helps users understand what the API does. It is also where we provide the documentation license ([Deed - Attribution-NonCommercial-NoDerivatives 4.0 International - Creative Commons](https://creativecommons.org/licenses/by-nc-nd/4.0/)). |
| `license`        | [License information](https://spec.openapis.org/oas/latest#license-object "https://spec.openapis.org/oas/latest#license-object") for the API (which is distinct from the documentation license).                                                                                                                                                  |
| `title`          | The title of the API                                                                                                                                                                                                                                                                                                                              |
| `version`        | The version of the document (which is distinct from the OpenAPI specification version and the API implementation version)                                                                                                                                                                                                                         |
| `x-feedbackLink` | This specialization extension enables us to collect feedback about the document. The URL should take readers to a GitHub issue template so they can create an issue. Refer to [Get feedback from users](https://docs.bump.sh/help/publish-documentation/feedback/)                                                                                |


## Add OpenAPI specification version

You must specify the version number of the OpenAPI specification that the OpenAPI document uses. This value is not related to the API `version` string in the [document info](#add-openapi-document-info).
Elastic OpenAPI documents span versions from Swagger 2.0 to OpenAPI 3.1.
Learn more about the [OpenAPI object](https://spec.openapis.org/oas/latest#openapi-object).

## Add operation identifiers

The `operationId` uniquely identifies the operation.
It is case sensitive and must be unique in the OpenAPI document.
When adding operation identifiers:
- Ensure each operation has a unique `operationId`
- Make `operationId` values that are acceptable for use in URLs (no special characters)
- Use consistent naming patterns across related operations


## Group APIs with tags

We use [tags](https://swagger.io/docs/specification/v3_0/grouping-operations-with-tags/) to group APIs by feature.
There are two types of tags:

| Tag type            | Purpose                                                | Notes                                                                      |
|---------------------|--------------------------------------------------------|----------------------------------------------------------------------------|
| **Document-level**  | Define the available tag categories for the entire API | - Use human-readable names- Add descriptions- Order affects navigation     |
| **Operation-level** | Assign each endpoint to a category                     | - Use tags from document-level list- Each operation needs at least one tag |

**Best practices:**
- Use **consistent tag names** across your entire API
- Use **one tag per operation** for cleaner navigation
- Use **sentence case** for tag names (use `x-displayName` to override the actual tag name if necessary)
- **Order tags logically** to create intuitive navigation flow


### Examples

<tab-set>
  <tab-item title="OpenAPI">
    ```yaml
    paths:
      /indices:
        post:
          summary: Create an index
          tags: ["Index management"]
          description: Creates a new index with optional settings and mappings
      /indices/{index}:
        delete:
          summary: Delete an index
          tags: ["Index management"]  
          description: Removes an index and all its data
      /indices/{index}/_settings:
        put:
          summary: Update index settings
          tags: ["Index management"]
          description: Modifies settings for an existing index
    ```
    **Define tag metadata** in the top-level `tags` section. Write a description for each tag to clarify its purpose:
    ```yaml
    tags:
      - name: "Index management"
        description: Operations for creating, configuring, and managing indices
      - name: "Search"
        description: Operations for querying and retrieving documents
      - name: "Document operations"
        description: Operations for creating, updating, and deleting individual documents
    ```
  </tab-item>

  <tab-item title="Elasticsearch">
    **Default namespace behavior**The compiler extracts the namespace from your endpoint name using everything before the first dot:
    - `indices.create` → `"indices"` tag
    - `search.template` → `"search"` tag
    - `cluster.health` → `"cluster"` tag
    - `ping` → `"ping"` tag (no dot, uses full name)
    This automatic grouping works well when your namespace matches how users think about the API functionality.**Overriding defaults with `@doc_tag`**Use the `@doc_tag` annotation when the automatic namespace doesn't match user expectations or when you want more descriptive groupings:
    ```ts
    /**
     * @rest_spec_name indices.create
     * @doc_tag "Index management"
     */
    export interface Request extends RequestBase {
      // ...
    }
    ```
    This moves the operation from an "indices" section to an "Index management" section.**Add new tags**If you create a new tag value, you must also add it to the [elasticsearch-shared-overlays.yaml](https://github.com/elastic/elasticsearch-specification/blob/main/docs/overlays/elasticsearch-shared-overlays.yaml) file. You can see all existing tag values in that file.Use **sentence case** for tag names. If you need different casing in the final docs, use the `x-displayName` extension in the overlay file.
    <note>
      Each operation can only have one tag, even though the OpenAPI specification supports multiple tags. This is a deliberate system constraint to keep the docs navigation clean and predictable.
    </note>
  </tab-item>
</tab-set>


## Extend OpenAPI documents

Per [OpenAPI Specification v3.0.3](https://spec.openapis.org/oas/v3.0.3#specification-extensions):
_"While the OpenAPI Specification tries to accommodate most use cases, additional data can be added to extend the specification at certain points."_
The extensions properties are implemented as patterned fields that are always prefixed by `x-`.
The following extensions are currently used in Elastic OpenAPI documents:

| **Field**        | **Description**                                                                                                                                                                 |
|------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `x-beta`         | Indicates that something is in beta. **Note:** Use `x-state` instead.                                                                                                           |
| `x-codeSamples`  | Defines code examples and their programming language. [Docs](https://docs.bump.sh/help/specification-support/doc-code-samples/)                                                 |
| `x-displayName`  | Overrides tag names at the document level to align with documentation standards.                                                                                                |
| `x-feedbackLink` | Adds a link for users to send feedback. [Docs](https://docs.bump.sh/help/publish-documentation/feedback/)                                                                       |
| `x-model`        | Used to abbreviate deeply nested/recursive API sections (for example, Elasticsearch query DSL). Should include an `externalDocs` link. Currently only applied through overlays. |
| `x-state`        | Indicates lifecycle state (for example, “Technical preview; added in 9.1.0”). Appears next to the operation or property.                                                        |
| `x-topics`       | Adds extra pages after the introduction. [Docs](https://docs.bump.sh/help/enhance-documentation-content/topics/)                                                                |


## Specify API lifecycle status

In Elastic OpenAPI documents, lifecycle status is communicated through the standard `deprecated` field and the `x-state` extension.
These annotations indicate deployment compatibility, stability level, and version information.

### Examples

<tab-set>
  <tab-item title="OpenAPI">
    **Availability and stability** is specified using the `x-state` extension property:
    ```yaml
    paths:
      /indices/{index}:
        get:
          summary: Get index information
          x-state: "Generally available; Added in 7.10.0"
          # ...

      /ml/anomaly_detection/{jobId}/_forecast:
        post:
          summary: Create anomaly detection forecast
          x-state: "Beta; Added in 8.5.0"
          # ...
    ```
    **Deprecation notices** use the standard OpenAPI `deprecated` boolean field:
    ```yaml
    components:
      schemas:
        IndexSettings:
          type: object
          properties:
            blocks:
              type: object
              deprecated: true
              description: |
                Deprecated in 8.0.0. Use 'index.blocks.read_only' instead.
                Controls read/write blocks on the index.
    ```
  </tab-item>

  <tab-item title="Elasticsearch">
    **API availability** is specified using the `@availability` annotation:
    ```ts
    /**
     * @availability stack since=7.7.0 stability=stable
     * @availability serverless stability=stable visibility=public
     */
    class FooRequest {
      bar: string
      /**
       * @availability stack since=9.3.0 stability=experimental
       */
      baz: string
      faz: string
    }
    ```
    Parameter and property-level `@availability` annotations are necessary in specific scenarios:
    1. **Mixed deployment availability**: When an API supports both serverless and stateful deployments, but some parameters or properties are only available in one deployment type
    2. **Later additions**: When a parameter or property is added after the initial API release, making its availability later than the API-level availability
    API stability is indicated using the `stability` parameter, which maps to the following `x-state` labels:
    - **`stability=stable`** (default) → "Generally available"
    - **`stability=beta`** → "Beta"
    - **`stability=experimental`** → "Technical preview"

    <important>
      The `since` field indicates is only available for `stack` and indicates when the API, parameter, or property was introduced. If the API is introduced in multiple major versions (for example: `8.19.0` and `9.1.0`), use the appropriate value in each branch.
    </important>
    **Deprecation notices** use the `@deprecated` annotation:
    ```ts
    class Foo {
      bar: string
      /** @deprecated 7.0.0 */
      baz?: string
      faz: string
    }
    ```
    You can add an optional description explaining the deprecation:
    ```ts
    class Foo {
      bar: string
      /** @deprecated 7.0.0 'baz' has been deprecated, use 'bar' instead */
      baz?: string
      faz: string
    }
    ```
  </tab-item>
</tab-set>

<important>
  Because we now only publish API docs for major versions (v8, v9) and not for minor versions (8.1, 8.2, and so on), always include the full version information in your `x-state` labels. For example: "Technical preview; added in 9.1.0."
</important>


## Document required permissions

Required permissions aren't part of the standard OpenAPI specification, but they can be documented in operation descriptions.
In Elasticsearch, we use annotations that generate structured permission documentation.

### Examples

<tab-set>
  <tab-item title="OpenAPI">
    Add permission requirements to the operation description using markdown formatting:
    ```yaml
    paths:
      /indices/{index}:
        put:
          summary: Create index
          description: |
            Creates a new index with optional settings and mappings.

            ## Required authorization

            * Index privileges: `create_index`, `manage`
    ```
    For APIs requiring multiple permission types:
    ```yaml
    paths:
      /indices/{index}/_stats:
        get:
          summary: Get index statistics
          description: |
            Returns statistics about one or more indices.

            ## Required authorization

            * Index privileges: `monitor`, `view_index_metadata`
            * Cluster privileges: `monitor`
    ```
  </tab-item>

  <tab-item title="Elasticsearch">
    **Index-level permissions** use the `@index_privileges` annotation:
    ```ts
    /**
     * @rest_spec_name indices.create
     * @availability stack since=0.0.0 stability=stable
     * @index_privileges create_index, manage
     */
    export interface Request extends RequestBase {
     // ...
    }
    ```
    This generates the following markdown section in the operation description:
    ```markdown
    ## Required authorization

    * Index privileges: `create_index`, `manage`
    ```
    **Cluster-level permissions** use the `@cluster_privileges` annotation:
    ```ts
    /**
     * @rest_spec_name cluster.state
     * @availability stack since=1.3.0 stability=stable
     * @cluster_privileges monitor, manage
     */
    export interface Request extends RequestBase {
     // ...
    }
    ```
    This adds:
    ```markdown
    ## Required authorization

    * Cluster privileges: `monitor`, `manage`
    ```
    **Combined privileges** use both annotations together:
    ```ts
    /**
     * @rest_spec_name indices.analyze
     * @index_privileges read
     * @cluster_privileges monitor
     */
    export interface Request extends RequestBase {
     // ...
    }
    ```
    This creates:
    ```markdown
    ## Required authorization

    * Index privileges: `read`
    * Cluster privileges: `monitor`
    ```

    <note>
      The annotation system doesn't support "OR" relationships between privileges. When multiple privileges are listed, they appear as if all are required. Use only the minimum necessary privileges for each operation to avoid confusion.
    </note>
  </tab-item>
</tab-set>