> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getbifrost.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Update adaptive routing settings (deprecated path)

> Replaces every adaptive routing setting and applies the change on every node in the cluster.
A switch left out of the body is turned off. `history_retention_days` applies from the next
restart; every other setting applies at once.

Returns `400` when the body is not valid JSON, when `snapshot_persist_interval_seconds` is
missing or outside 5 to 86400, when `history_retention_days` is missing or outside 1 to 30,
or when `reroute_target` is any value other than `pool` or `fallbacks`; an omitted or empty
`reroute_target` is stored as `pool`.

Deprecated: use `PUT /api/adaptive-routing/config`. Every response from this alias, errors
included, carries `Link: </api/adaptive-routing/config>; rel="successor-version"` and a
`Warning: 299` header naming the replacement.


<Warning>
  This path is deprecated and will be removed in the following major release.
  Use `/api/adaptive-routing/config` instead.
</Warning>

<Note>
  This endpoint is available in [Bifrost Enterprise](https://www.getmaxim.ai/bifrost/enterprise) only.
</Note>

**Required Permissions**

| Permission | Granted via |
| - | - |
| `AdaptiveRouter:Update` | RBAC role or API key scope |

[How permissions work](/api/procuring-api-keys#required-permissions)


## OpenAPI

````yaml /openapi/openapi.json put /api/load-balancer-config
openapi: 3.1.0
info:
  title: Bifrost API
  description: >
    Bifrost HTTP Transport API for AI model inference and gateway management.


    This API provides a unified interface for interacting with multiple AI
    providers

    including OpenAI, Anthropic, Bedrock, Gemini, and more through a single API,

    along with comprehensive management APIs for configuring and monitoring the
    gateway.


    ## API Structure


    ### Unified Inference API (`/v1/*`)

    The primary API using Bifrost's unified format. Model parameters use the
    format

    `provider/model` (e.g., `openai/gpt-4`, `anthropic/claude-3-opus`).


    ### Async Inference API (`/v1/async/*`)

    Submit inference requests for asynchronous execution. Returns a job ID
    immediately

    and allows polling for results. Supports all inference types except batches,
    files,

    and containers.


    ### Provider Integration APIs

    Native provider-format APIs for drop-in compatibility:

    - `/openai/*` - OpenAI-compatible API

    - `/anthropic/*` - Anthropic-compatible API

    - `/genai/*` - Google GenAI (Gemini) compatible API

    - `/bedrock/*` - AWS Bedrock compatible API

    - `/cohere/*` - Cohere compatible API


    ### Framework Integration APIs

    Multi-provider proxy endpoints for AI frameworks:

    - `/litellm/*` - LiteLLM proxy with all provider formats

    - `/langchain/*` - LangChain compatible endpoints

    - `/pydanticai/*` - PydanticAI compatible endpoints


    ### Management APIs (`/api/*`)

    APIs for managing and monitoring the Bifrost gateway:

    - `/api/config` - Configuration management

    - `/api/providers` - Provider and API key management

    - `/api/plugins` - Plugin management

    - `/api/governance/*` - Virtual keys, teams, customers, budgets, rate
    limits, routing rules, and pricing overrides

    - `/api/logs` - Log search and analytics

    - `/api/mcp/*` - MCP (Model Context Protocol) client management

    - `/api/session/*` - Authentication and session management

    - `/api/cache/*` - Cache management

    - `/health` - Health check endpoint


    ## Fallbacks

    Requests can include fallback models that will be tried if the primary model
    fails.
  version: 1.0.0
  contact:
    name: Contact Us
    url: https://getmaxim.ai/bifrost
  license:
    name: Apache 2.0
    url: https://opensource.org/licenses/Apache-2.0
servers:
  - url: '{baseUrl}'
    description: Your Bifrost instance
    variables:
      baseUrl:
        default: http://localhost:8080
        description: Base URL of your Bifrost instance (e.g. https://bifrost.mycompany.com)
security:
  - BearerAuth: []
  - BasicAuth: []
  - ApiKeyAuth: []
tags:
  - name: Agent Gateway
    description: >-
      Agent registrations, A2A protocol calls, push callbacks, and operation
      history
  - name: Models
    description: Model listing and information
  - name: Chat Completions
    description: Chat-based text generation
  - name: Text Completions
    description: Text completion generation
  - name: Responses
    description: OpenAI Responses API compatible endpoints
  - name: OCR
    description: Optical character recognition for documents and images
  - name: Rerank
    description: Document reranking by relevance to a query
  - name: Decisions
    description: Structured decisions evaluated against annotated function-tool definitions
  - name: Embeddings
    description: Text embedding generation
  - name: Images
    description: Image generations, editing, and variations
  - name: Videos
    description: Video generation and management
  - name: Audio
    description: Speech synthesis and transcription
  - name: Count Tokens
    description: Token counting utilities
  - name: Batch
    description: Batch processing operations
  - name: Files
    description: File management operations
  - name: Containers
    description: Container management operations
  - name: Async Jobs
    description: Asynchronous job submission and retrieval endpoints
  - name: Realtime
    description: Realtime WebSocket and WebRTC endpoints
  - name: OpenAI Integration
    description: OpenAI-compatible API endpoints (/openai/*)
  - name: Azure Integration
    description: Azure OpenAI integration endpoints
  - name: Anthropic Integration
    description: Anthropic-compatible API endpoints (/anthropic/*)
  - name: GenAI Integration
    description: Google GenAI (Gemini) compatible API endpoints (/genai/*)
  - name: Bedrock Integration
    description: AWS Bedrock compatible API endpoints (/bedrock/*)
  - name: Cohere Integration
    description: Cohere compatible API endpoints (/cohere/*)
  - name: Typesafe Integration
    description: Typesafe compatible API endpoints (/typesafe/*)
  - name: LiteLLM Integration
    description: LiteLLM proxy endpoints with multi-provider support (/litellm/*)
  - name: LangChain Integration
    description: LangChain compatible endpoints with multi-provider support (/langchain/*)
  - name: PydanticAI Integration
    description: >-
      PydanticAI compatible endpoints with multi-provider support
      (/pydanticai/*)
  - name: Health
    description: Health check endpoints
  - name: Configuration
    description: Configuration management endpoints
  - name: Session
    description: Session and authentication endpoints
  - name: Providers
    description: Provider management endpoints
  - name: Plugins
    description: Plugin management endpoints
  - name: MCP
    description: Model Context Protocol endpoints
  - name: Governance
    description: Virtual keys, teams, and customers management
  - name: Routing
    description: Routing rules and complexity analyzer configuration
  - name: Logging
    description: Log search and management endpoints
  - name: Cache
    description: Cache management endpoints
  - name: Vault
    description: Vault secret management endpoints
  - name: Skills
    description: Skills Repository management, marketplace, and download endpoints
  - name: Audit Logs
    description: >-
      CADF-compliant audit log search, export, and signature verification
      endpoints
  - name: Webhooks
    description: Webhook endpoint management and signed async-job delivery history
  - name: Notifications
    description: >-
      Role-targeted dashboard notifications, delivered over the dashboard
      WebSocket
  - name: Background Jobs
    description: >-
      Status, progress and cancellation of durable background jobs (cost
      recalculation, Warp log indexing, and others)
  - name: Warp
    description: >-
      Configuration for Warp, the dashboard agent that answers questions about
      the deployment's own telemetry
paths:
  /api/load-balancer-config:
    put:
      tags:
        - Adaptive Routing
      summary: Update adaptive routing settings (deprecated path)
      description: >
        Replaces every adaptive routing setting and applies the change on every
        node in the cluster.

        A switch left out of the body is turned off. `history_retention_days`
        applies from the next

        restart; every other setting applies at once.


        Returns `400` when the body is not valid JSON, when
        `snapshot_persist_interval_seconds` is

        missing or outside 5 to 86400, when `history_retention_days` is missing
        or outside 1 to 30,

        or when `reroute_target` is any value other than `pool` or `fallbacks`;
        an omitted or empty

        `reroute_target` is stored as `pool`.


        Deprecated: use `PUT /api/adaptive-routing/config`. Every response from
        this alias, errors

        included, carries `Link: </api/adaptive-routing/config>;
        rel="successor-version"` and a

        `Warning: 299` header naming the replacement.
      operationId: updateAdaptiveRoutingConfigLegacy
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: >
                The adaptive routing settings. On `PUT` this is a full
                replacement: a switch left out of the

                body is turned off, and `history_retention_days` and
                `snapshot_persist_interval_seconds` must

                be sent. Unknown fields are ignored.
              required:
                - history_retention_days
                - snapshot_persist_interval_seconds
              properties:
                direction_selection_enabled:
                  type: boolean
                  description: >-
                    Adaptive provider selection. Reads `true` on a fresh
                    install.
                route_selection_enabled:
                  type: boolean
                  description: Adaptive key selection. Reads `true` on a fresh install.
                append_fallbacks_to_pinned:
                  type: boolean
                  description: >-
                    Add healthy fallbacks to requests that already name a
                    provider. Reads `false` on a fresh install.
                reroute_failed_directions:
                  type: boolean
                  description: >-
                    Redirect requests that name a failing provider. Reads
                    `false` on a fresh install.
                reroute_target:
                  type: string
                  enum:
                    - pool
                    - fallbacks
                  default: pool
                  description: >
                    Where a redirected request goes. `pool` picks among the
                    eligible providers adaptive routing

                    scores; `fallbacks` takes the request's first configured
                    fallback that is not failing.

                    An omitted or empty value is stored as `pool`. Any other
                    value is rejected with `400`.
                prune_failed_fallbacks:
                  type: boolean
                  description: >-
                    Skip failing providers in a request's configured fallbacks.
                    Reads `false` on a fresh install.
                history_enabled:
                  type: boolean
                  description: Record routing history. Reads `true` on a fresh install.
                history_retention_days:
                  type: integer
                  minimum: 1
                  maximum: 30
                  default: 7
                  description: >-
                    Days routing history is kept. A change applies from the next
                    restart. Outside 1 to 30, or omitted, is rejected with
                    `400`.
                snapshot_persist_interval_seconds:
                  type: integer
                  minimum: 5
                  maximum: 86400
                  default: 300
                  description: >-
                    How often routing state is saved, in seconds. Outside 5 to
                    86400, or omitted, is rejected with `400`.
      responses:
        '200':
          description: >-
            Settings saved and applied. Returns the saved settings, with an
            omitted `reroute_target` stored as `pool`.
          headers:
            Link:
              description: '`</api/adaptive-routing/config>; rel="successor-version"`'
              schema:
                type: string
            Warning:
              description: >-
                `299 - "The /api/load-balancer-config API is deprecated; use
                /api/adaptive-routing/config"`
              schema:
                type: string
          content:
            application/json:
              schema:
                type: object
                description: >
                  The adaptive routing settings. On `PUT` this is a full
                  replacement: a switch left out of the

                  body is turned off, and `history_retention_days` and
                  `snapshot_persist_interval_seconds` must

                  be sent. Unknown fields are ignored.
                required:
                  - history_retention_days
                  - snapshot_persist_interval_seconds
                properties:
                  direction_selection_enabled:
                    type: boolean
                    description: >-
                      Adaptive provider selection. Reads `true` on a fresh
                      install.
                  route_selection_enabled:
                    type: boolean
                    description: Adaptive key selection. Reads `true` on a fresh install.
                  append_fallbacks_to_pinned:
                    type: boolean
                    description: >-
                      Add healthy fallbacks to requests that already name a
                      provider. Reads `false` on a fresh install.
                  reroute_failed_directions:
                    type: boolean
                    description: >-
                      Redirect requests that name a failing provider. Reads
                      `false` on a fresh install.
                  reroute_target:
                    type: string
                    enum:
                      - pool
                      - fallbacks
                    default: pool
                    description: >
                      Where a redirected request goes. `pool` picks among the
                      eligible providers adaptive routing

                      scores; `fallbacks` takes the request's first configured
                      fallback that is not failing.

                      An omitted or empty value is stored as `pool`. Any other
                      value is rejected with `400`.
                  prune_failed_fallbacks:
                    type: boolean
                    description: >-
                      Skip failing providers in a request's configured
                      fallbacks. Reads `false` on a fresh install.
                  history_enabled:
                    type: boolean
                    description: Record routing history. Reads `true` on a fresh install.
                  history_retention_days:
                    type: integer
                    minimum: 1
                    maximum: 30
                    default: 7
                    description: >-
                      Days routing history is kept. A change applies from the
                      next restart. Outside 1 to 30, or omitted, is rejected
                      with `400`.
                  snapshot_persist_interval_seconds:
                    type: integer
                    minimum: 5
                    maximum: 86400
                    default: 300
                    description: >-
                      How often routing state is saved, in seconds. Outside 5 to
                      86400, or omitted, is rejected with `400`.
        '400':
          description: Bad request
          headers:
            Link:
              description: '`</api/adaptive-routing/config>; rel="successor-version"`'
              schema:
                type: string
            Warning:
              description: >-
                `299 - "The /api/load-balancer-config API is deprecated; use
                /api/adaptive-routing/config"`
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BifrostError'
        '403':
          description: Forbidden. Authenticated, but not permitted to perform this action.
          headers:
            Link:
              description: '`</api/adaptive-routing/config>; rel="successor-version"`'
              schema:
                type: string
            Warning:
              description: >-
                `299 - "The /api/load-balancer-config API is deprecated; use
                /api/adaptive-routing/config"`
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BifrostError'
        '500':
          description: >-
            The settings could not be saved, or were saved but could not be
            applied.
          headers:
            Link:
              description: '`</api/adaptive-routing/config>; rel="successor-version"`'
              schema:
                type: string
            Warning:
              description: >-
                `299 - "The /api/load-balancer-config API is deprecated; use
                /api/adaptive-routing/config"`
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BifrostError'
      deprecated: true
      security:
        - ManagementBearerAuth: []
        - BasicAuth: []
components:
  schemas:
    BifrostError:
      type: object
      description: Error response from Bifrost
      properties:
        event_id:
          type: string
        type:
          type: string
        is_bifrost_error:
          type: boolean
        status_code:
          type: integer
        error:
          $ref: '#/components/schemas/ErrorField'
        extra_fields:
          $ref: '#/components/schemas/BifrostErrorExtraFields'
    ErrorField:
      type: object
      properties:
        type:
          type: string
        code:
          type: string
        message:
          type: string
        param:
          type: string
        event_id:
          type: string
    BifrostErrorExtraFields:
      type: object
      properties:
        routing_info:
          $ref: '#/components/schemas/RoutingInfo'
        provider:
          $ref: '#/components/schemas/ModelProvider'
          deprecated: true
          description: 'Deprecated: use routing_info.provider.'
        original_model_requested:
          type: string
          deprecated: true
          description: >-
            Deprecated: use routing_info.primary_model when
            routing_info.is_fallback is true, otherwise routing_info.model. For
            the model the caller asked for, read routing_info.requested_model.
        resolved_model_used:
          type: string
          deprecated: true
          description: >-
            Deprecated: use routing_info.resolved_key_alias.model_id when an
            alias matched, otherwise routing_info.model.
        request_type:
          type: string
        mcp_request_type:
          type: string
        a2a_request_type:
          type: string
          description: Agent Gateway operation, for A2A errors
        a2a_agent_name:
          type: string
        error_type:
          type: string
          description: >-
            Normalized, low-cardinality classification of why the request
            failed, declared by whichever component refused it. Prefixed by
            fault domain (caller_, policy_, provider_, bifrost_). Absent on
            failures that were not classified at source.
        retry_after_ms:
          type: integer
          format: int64
          minimum: 1000
          maximum: 300000
          description: >-
            The provider's hint for how long to wait before retrying, in
            milliseconds, read from its retry-after-ms or Retry-After header or
            its google.rpc.RetryInfo error detail, and clamped to between 1000
            and 300000. Absent when the provider gave no explicit hint.
        raw_request:
          description: Raw provider request, when raw request capture is enabled
        raw_response:
          description: Raw provider response, when raw response capture is enabled
        converted_request_type:
          type: string
        dropped_compat_plugin_params:
          type: array
          items:
            type: string
        latency:
          type: integer
          format: int64
          description: Latency in milliseconds
        key_statuses:
          type: array
          description: >-
            Per-key results, for requests that ran on every key such as listing
            models
          items:
            type: object
            properties:
              key_id:
                type: string
              status:
                type: string
                enum:
                  - success
                  - list_models_failed
              provider:
                $ref: '#/components/schemas/ModelProvider'
              error:
                $ref: '#/components/schemas/BifrostError'
        mcp_auth_required:
          type: object
          description: >-
            Set when a per-user MCP tool needs the caller to complete an inline
            auth flow
          properties:
            kind:
              type: string
            mcp_client_id:
              type: string
            mcp_client_name:
              type: string
            message:
              type: string
            authorize_url:
              type: string
            session_id:
              type: string
        billed_usage:
          $ref: '#/components/schemas/BifrostLLMUsage'
          description: >-
            Usage the provider reported and billed even though the request
            failed
    RoutingInfo:
      type: object
      description: >-
        Which provider, model and key handled the attempt that produced this
        response or error, and what the caller asked for. Also sent as
        x-bifrost-routing-info-* response headers.
      properties:
        provider:
          $ref: '#/components/schemas/ModelProvider'
          description: Provider that ran the attempt
        model:
          type: string
          description: Model sent to that provider
        key:
          type: string
          description: Name of the stored key used, never its ID or secret
        resolved_key_alias:
          $ref: '#/components/schemas/ResolvedKeyAlias'
        is_fallback:
          type: boolean
          description: >-
            True when a fallback served the request or returned the error.
            Omitted when false.
        primary_provider:
          $ref: '#/components/schemas/ModelProvider'
          description: The primary attempt's provider. Set only when a fallback ran.
        primary_model:
          type: string
          description: The primary attempt's model. Set only when a fallback ran.
        requested_provider:
          $ref: '#/components/schemas/ModelProvider'
          description: >-
            Provider the caller asked for, before routing rules, load balancing
            or session affinity changed it. Omitted when the caller sent a bare
            model.
        requested_model:
          type: string
          description: Model the caller asked for, before anything changed it
        server_side_fallback_model:
          type: string
          description: Model that answered when Anthropic switched models inside one call
    ModelProvider:
      type: string
      description: AI model provider identifier
      enum:
        - anthropic
        - azure
        - bedrock
        - bedrock_mantle
        - cerebras
        - cohere
        - deepseek
        - gemini
        - groq
        - mistral
        - ollama
        - opencode-go
        - opencode-zen
        - openai
        - parasail
        - perplexity
        - sgl
        - vertex
        - openrouter
        - elevenlabs
        - huggingface
        - nebius
        - xai
        - replicate
        - vllm
        - runway
        - runware
        - fireworks
        - sarvam
        - wafer
        - databricks
        - cloudflare
        - typesafe
    BifrostLLMUsage:
      type: object
      description: Token usage information
      properties:
        prompt_tokens:
          type: integer
          description: >
            Total input tokens including any prompt-cache tokens (read + write).
            Subtract prompt_tokens_details.cached_read_tokens and
            prompt_tokens_details.cached_write_tokens to get the non-cached
            portion.
        prompt_tokens_details:
          $ref: '#/components/schemas/ChatPromptTokensDetails'
        completion_tokens:
          type: integer
          description: Number of output/completion tokens generated.
        completion_tokens_details:
          $ref: '#/components/schemas/ChatCompletionTokensDetails'
        total_tokens:
          type: integer
        tool_usage:
          type: object
          description: |
            Counts of provider-hosted (server-side) tool calls billed per call.
          properties:
            web_search:
              type: object
              properties:
                num_requests:
                  type: integer
                  description: Number of billable web search calls.
        cost:
          $ref: '#/components/schemas/BifrostCost'
    ResolvedKeyAlias:
      type: object
      description: Set only when the requested model matched a model alias on the key
      required:
        - model_id
      properties:
        model_id:
          type: string
          description: Model ID sent to the provider
        model_name:
          type: string
          description: Canonical model name, used for pricing and logs
        model_family:
          type: string
          description: Resolved model family
    ChatPromptTokensDetails:
      type: object
      properties:
        text_tokens:
          type: integer
        audio_tokens:
          type: integer
        image_tokens:
          type: integer
        cached_read_tokens:
          type: integer
          description: >
            Tokens served from the prompt cache (cache hit). These tokens are
            already included in prompt_tokens and are billed at the reduced
            cache-read rate. Populated for all providers that support prompt
            caching (Anthropic, Bedrock, OpenAI, Gemini, xAI, etc.).
        cached_write_tokens:
          type: integer
          description: >
            Tokens written to the prompt cache on this request (cache creation /
            write). These tokens are already included in prompt_tokens and are
            billed at the cache-creation rate. Populated for providers that
            separately report cache write tokens (Anthropic, Bedrock).
    ChatCompletionTokensDetails:
      type: object
      properties:
        text_tokens:
          type: integer
        accepted_prediction_tokens:
          type: integer
        audio_tokens:
          type: integer
        citation_tokens:
          type: integer
        num_search_queries:
          type: integer
          deprecated: true
          description: >-
            Deprecated, use tool_usage.web_search.num_requests. Will be removed
            in 3.0.0.
        reasoning_tokens:
          type: integer
        image_tokens:
          type: integer
        rejected_prediction_tokens:
          type: integer
    BifrostCost:
      type: object
      description: Cost breakdown for the request
      properties:
        input_tokens_cost:
          type: number
        output_tokens_cost:
          type: number
        reasoning_tokens_cost:
          type: number
          description: Cost for reasoning/thinking tokens (reasoning models)
        citation_tokens_cost:
          type: number
          description: Cost for citation tokens
        search_queries_cost:
          type: number
          description: Cost for web search queries
        request_cost:
          type: number
        total_cost:
          type: number
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: >
        Bearer token authentication. Use your provider API key or Bifrost
        authentication token.

        Virtual keys (prefixed with `sk-bf-`) can also be passed here.
    BasicAuth:
      type: http
      scheme: basic
      description: >
        Basic authentication using the Bifrost admin username and password

        (`auth_config.admin_username` / `auth_config.admin_password`).

        Accepted on management APIs (`/api/*`, `/metrics`, `/ws`) only - the
        inference

        middleware never validates Basic credentials.
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: |
        API key authentication via the `x-api-key` header.
        Virtual keys (prefixed with `sk-bf-`) can also be passed here.
    ManagementBearerAuth:
      type: http
      scheme: bearer
      description: >
        Management API authentication for `/api/*` endpoints. Use the
        `Authorization` header

        with `Bearer <token>`, where `<token>` is one of:


        - a Bifrost management API key,

        - a dashboard session token issued by `POST /api/session/login`,

        - base64 of `<admin-username>:<admin-password>` (legacy equivalent of
        `BasicAuth`).


        Virtual keys (`sk-bf-*`) and the `x-api-key` header are not accepted on
        management APIs -

        the sole exception is `GET /api/governance/virtual-keys/quota`, which is
        virtual-key-only.


        Authentication alone is not sufficient in Bifrost Enterprise: each
        operation page shows a

        **Required Permissions** table (`Resource:Operation`, for example
        `Dashboard:View`) above

        its Authorizations section, and the caller's RBAC role or management API
        key scopes must

        include what it lists, otherwise the request is rejected with `403
        Forbidden`.


        A local admin — authenticated with the admin password, or any caller on
        a deployment with

        dashboard auth disabled — bypasses these checks and can call every
        management endpoint.


        **OSS setup lock.** On Bifrost OSS, while dashboard auth is not active
        (no admin account,

        or auth disabled), every management endpoint except the public ones
        (`/health`,

        `/api/version`, `/api/session/is-auth-enabled`, `/api/session/login`,
        ...) requires the

        operator's setup token in the `X-Bifrost-Setup-Token` header, in place
        of `Authorization`.

        The token is set with `setup_token` in `config.json` or the
        `BIFROST_SETUP_TOKEN`

        environment variable. A missing header returns `401`, a wrong token
        `403`. The header

        stops working once dashboard auth is enabled. The dashboard instead
        trades the token once

        for an HttpOnly `bifrost_setup_session` cookie via `POST
        /api/session/setup`.

        See [Required permissions](/api/procuring-api-keys#required-permissions)
        for how

        permissions are derived and which endpoints are exempt.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.