﻿---
title: Contribute to Kibana API docs locally
description: Set up a local Kibana API docs workflow, from cloning the repo to linting and previewing merged OpenAPI documentation.
url: https://www.elastic.co/elastic/docs-builder/docs/3028/contribute-docs/api-docs/kibana-api-docs-quickstart
applies_to:
  - Elastic Cloud Serverless: Generally available
  - Elastic Stack: Generally available
---

# Contribute to Kibana API docs locally
## Overview

The Kibana API documentation is created by merging multiple OpenAPI documents. This is a step-by-step local development workflow. While CI runs these steps automatically on PR branches in the `kibana` repo, working locally enables you to validate, preview and debug before submitting your changes.
The workflow you follow depends on which set of APIs you're updating:
<tab-set>
  <tab-item title="Code-generated">
    The core Kibana APIs are automatically generated from TypeScript route definitions in the codebase. Edit the `.ts` files in your plugin, and CI will regenerate the OpenAPI files when you push your PR. You can also run the generation locally for validation.
  </tab-item>

  <tab-item title="Manual YAML">
    Some teams, including Security and Observability, work with hand-edited YAML files in their plugin and package directories. For the complete list of files, refer to the [merge scripts](https://github.com/elastic/kibana/tree/main/oas_docs/scripts).
  </tab-item>
</tab-set>

For more details, refer to the Kibana [OAS docs README](https://github.com/elastic/kibana/tree/main/oas_docs#kibana-api-reference-documentation).

## Quickstart

Follow these steps to contribute to Kibana API docs locally:
<stepper>
  <step title="Clone the repository">
    1. [Fork the Kibana repository](https://github.com/elastic/kibana/fork) to your GitHub account.
    2. Clone your fork locally:
       ```bash
       git clone https://github.com/YOUR_USERNAME/kibana.git
       cd kibana
       ```
  </step>

  <step title="Prepare your environment">
    Run this command to set up your Node.js environment:
    ```bash
    nvm use
    ```
    If you don't have Node.js installed, refer to the [Kibana development getting started guide](https://www.elastic.co/docs/extend/kibana/development-getting-started).
  </step>

  <step title="Install dependencies">
    ```bash
    yarn kbn bootstrap
    ```

    <note>
      If dependencies are broken or bootstrap fails, run `yarn kbn clean` first. For more troubleshooting guidance, refer to the [Kibana development getting started guide](https://www.elastic.co/docs/extend/kibana/development-getting-started).
    </note>
  </step>

  <step title="Make your docs changes">
    <tab-set>
      <tab-item title="Code-generated">
        Edit the TypeScript route definitions in your plugin code. Add JSDoc comments, request/response schemas, and examples as needed, per the [checklist](https://www.elastic.co/elastic/docs-builder/docs/3028/contribute-docs/api-docs/checklist).**Always include version and lifecycle information** using the `availability` option in your route definitions. This powers the version badges and tech preview labels that help users understand when an API was introduced and its stability status.
        ```typescript
        options: {
          tags: ['example', 'oas-tag:Example APIs'],
          availability: {
            stability: 'experimental',
            since: '9.2.0',
          },
        },
        ```
        The `availability` option includes two fields:
        - **`stability`**: Indicates the lifecycle state of the API
          - `'experimental'` → Technical preview; can change or be removed in future versions
        - `'stable'` (default) → Generally available (GA); stable for production use
        - **`since`**: The version when the API was first added (for example, `'9.2.0'`)
        The `availability` option is only available at the API (route) level.
        For individual parameters, you must manually document version and lifecycle information in the parameter's description field.
        <note>
          **CI will automatically regenerate the OpenAPI files when you push your `.ts` changes.** The next two steps show how to capture the snapshot and add examples locally, which is useful for validating changes before pushing or debugging issues.
        </note>
      </tab-item>

      <tab-item title="Manual YAML">
        Edit the YAML files in the appropriate plugin or package directory. Refer to the README alongside each file for specific guidance on adding summaries, descriptions, tags, metadata, links, and examples.**Always include version and lifecycle information** using the `x-state` field. This powers the version badges and tech preview labels in the API docs.
        ```yaml
        x-state: Technical Preview; added in 9.2.0
        ```
        For stable/GA APIs, you can omit the lifecycle status:
        ```yaml
        x-state: added in 9.0.0
        ```
        In these README files, you'll also find instructions for generating intermediate bundle files that capture your changes, and that are later used to generate the full API documentation.The YAML files with the content changes and the intermediate bundle files are the minimum set of files required for creating a pull request. Without the intermediate bundle files, the automation won't pick up the changes and won't generate the full API documentation.Review the [checklist](https://www.elastic.co/elastic/docs-builder/docs/3028/contribute-docs/api-docs/checklist) for best practices.Once you've made your changes, skip the next two steps and proceed to generate the documentation.
      </tab-item>
    </tab-set>
  </step>

  <step title="Add examples to your routes">
    Concrete request and response examples significantly improve API documentation usability.
    <dropdown title="Inline TypeScript examples">
      For code-generated APIs, you can add examples directly in your route definitions. Examples are type-checked at development time, so shape errors are caught during authoring.
      ```typescript
      .addVersion({
        version: '2023-10-31',
        options: {
          oasOperationObject: () => ({
            requestBody: {
              content: {
                'application/json': {
                  examples: {
                    fooExample1: {
                      summary: 'An example foo request',
                      value: {
                        name: 'Cool foo!',
                      } as FooResource,
                    },
                  },
                },
              },
            },
          }),
        },
        // ...
      })
      ```
    </dropdown>

    <dropdown title="YAML examples">
      For code-generated APIs, you can reference a YAML file in your route definition:
      ```typescript
      import path from 'node:path';

      const oasOperationObject = () => path.join(__dirname, 'foo.examples.yaml');

      .addVersion({
        version: '2023-10-31',
        options: {
          oasOperationObject,
        },
        validate: {
          request: {
            body: fooResource,
          },
          response: {
            200: {
              body: fooResourceResponse,
            },
          },
        },
      })
      ```
      For manually-maintained OpenAPI documents, add examples directly in your YAML files in the appropriate plugin or package directory.**Example YAML structure:**
      ```yaml
      requestBody:
        content:
          application/json:
            examples:
              fooExample:
                summary: Foo example
                description: An example request of creating foo
                value:
                  name: 'Cool foo!'
                  enabled: true
      responses:
        200:
          content:
            application/json:
              examples:
                exampleResponse:
                  summary: Successful response
                  value:
                    id: '12345'
                    name: 'Cool foo!'
                    enabled: true
      x-codeSamples:
      - lang: cURL
        # label: A label which will be used as a title. Defaults to the lang value.
        source: |
          curl \
           -X POST "https://${KIBANA_URL}/api/foo" \
           -H "Authorization: ApiKey ${API_KEY}" \
           -H "kbn-xsrf: true" \
           -H "Content-Type: application/json" \
           -d '{
           ...
           }'
      - lang: Console
        source: |
          POST kbn:/api/agent_builder/tools
          {
           ...
          }
      ```
    </dropdown>
  </step>

  <step title="Optional: Capture code-generated output">
    <tab-set>
      <tab-item title="Code-generated">
        <note>
          **This step is optional.** CI will automatically capture the snapshot when you push your `.ts` changes. Running this locally is useful for validating changes before pushing or debugging issues.
        </note>
        This step captures the OpenAPI specification that Kibana generates at runtime from your route definitions. It spins up a local Elasticsearch and Kibana cluster with your code changes. This generates the following output files in the `oas_docs` directory:
        - `bundle.json`
        - `bundle.serverless.json`
        **Prerequisites:**
        - [Docker](https://docs.docker.com/get-docker/) must be running.
        To capture all the documented API paths, copy the command from [`capture_oas_snapshot.sh`](https://github.com/elastic/kibana/blob/main/.buildkite/scripts/steps/checks/capture_oas_snapshot.sh). For example:
        ```bash
        node scripts/capture_oas_snapshot \
          --include-path /api/status \
          --include-path /api/alerting/rule/ \
          --include-path /api/alerting/rules \
          --include-path /api/actions \
          --include-path /api/security/role \
          --include-path /api/spaces \
          --include-path /api/streams \
          --include-path /api/fleet \
          --include-path /api/saved_objects/_import \
          --include-path /api/saved_objects/_export \
          --include-path /api/maintenance_window \
          --include-path /api/agent_builder
          --update
        ```
        For faster iteration, you can capture the specific paths you're working on, though this minimized output should not be included in your pull request.
        For example:
        ```bash
        node scripts/capture_oas_snapshot --update --include-path /api/your/specific/path
        ```
      </tab-item>

      <tab-item title="Manual YAML">
        This step is not applicable for manually-maintained OpenAPI documents. Your YAML files are used directly. Skip to the next step.
      </tab-item>
    </tab-set>
  </step>

  <step title="Generate docs">
    Run these commands to merge the OpenAPI documentation files:
    ```bash
    cd oas_docs
    make api-docs
    ```
    This generates the following files:
    - `oas_docs/output/kibana.yaml`
    - `oas_docs/output/kibana.serverless.yaml`

    <tip>
      Use `make help` to see available commands.
    </tip>
  </step>

  <step title="Lint your docs">
    Run this command to lint your OpenAPI files:
    ```bash
    node ../scripts/validate_oas_docs.js
    ```
    You can limit the scope of APIs that the linter checks by using `--path` or `--only` options. For details and examples, add `--help`.
    <tip>
      When you open a pull request to submit API documentation changes, this linter runs in a CI check. It uses the `--assert-no-error-increase` option which causes the check to fail if the number of errors increases compared to the baseline.
    </tip>
  </step>

  <step title="Preview the API docs">
    Install [`bump-cli`](https://www.npmjs.com/package/bump-cli):
    ```bash
    npm install -g bump-cli
    ```
    Run this command to generate short-lived previews:
    ```bash
    make api-docs-preview
    ```
  </step>

  <step title="Open a pull request">
    Once you're satisfied with your docs changes, create a pull request:
    <tab-set>
      <tab-item title="Code-generated">
        You have two options:
        - Push only your `.ts` changes and let CI regenerate the OpenAPI files automatically
        - Push both your `.ts` changes and locally-generated OpenAPI files together
        The CI will validate your OpenAPI specs using the linter. Once approved, merge your changes and backport to the appropriate branches if needed.
      </tab-item>

      <tab-item title="Manual YAML">
        Push your edited YAML files. The CI will validate your OpenAPI specs using the linter. Once approved, merge your changes and backport to the appropriate branches if needed.
      </tab-item>
    </tab-set>
  </step>
</stepper>