openapi: 3.0.3
info:
  title: Sprinklenet Knowledge Spaces — Developer API
  version: 1.0.0
  x-logo:
    altText: Sprinklenet Knowledge Spaces
  description: "

    The **Knowledge Spaces Developer API** lets you embed AI chatbots, manage conversation

    sessions, and stream events into your own product — all backed by your organization's

    knowledge spaces.


    This is the **public, programmatic surface**. It is stable, versioned, and safe to build

    against. Internal dashboard/admin endpoints are intentionally excluded.


    ---


    ## Base URL


    ```

    https://spaces.sprinklenet.com/api

    ```


    All request paths in this document are relative to that base URL.


    ## Authentication


    Every request authenticates with an **organization API key**. Generate one in

    **Console → Settings → API Keys**. Keys are prefixed `ks_live_` and are shown **once** at

    creation — store them in a secret manager, never in client-side code or version control.


    Send the key on every request using **either** header form:


    ```http

    X-API-Key: ks_live_xxxxxxxxxxxxxxxxxxxx

    # or

    Authorization: Bearer ks_live_xxxxxxxxxxxxxxxxxxxx

    ```


    Requests without a valid key receive `401 Unauthorized`. Keys are scoped to a single

    organization; a key can only reach bots and sessions owned by that organization.


    ## Errors


    All errors use a consistent JSON envelope and standard HTTP status codes:


    ```json

    { \"success\": false, \"message\": \"Human-readable explanation\", \"code\": \"invalid_api_key\" }

    ```


    | Status | Meaning | When it happens |

    |--------|---------|-----------------|

    | `400` | Bad Request | Malformed body or missing required field |

    | `401` | Unauthorized | Missing or invalid API key |

    | `402` | Payment Required | Organization usage limit reached |

    | `403` | Forbidden | Key lacks access to this bot/session/scope |

    | `404` | Not Found | Resource does not exist |

    | `429` | Too Many Requests | Rate limit exceeded — see `Retry-After` |

    | `5xx` | Server Error | Transient issue on our side; retry with backoff |


    ## Rate limits


    The external API allows **100 requests per 15 minutes** per API key by default.

    When exceeded you receive `429` with a `Retry-After` header (seconds). Every response

    also carries `RateLimit-Limit`, `RateLimit-Remaining`, and `RateLimit-Reset` headers.

    Call `GET /rate-limit/info` for the live public policy.


    ## Versioning


    The API is versioned by contract. Breaking changes ship under a new major version and are

    announced ahead of time; additive changes (new fields, new endpoints) are rolled out without

    a version bump, so write **forward-compatible** clients that ignore unknown fields.


    ## Webhooks


    Subscribe to conversation and session events (`bot.conversation_started`, `session.ended`,

    `escalation.fired`, …) so your systems react in real time instead of polling. Each delivery

    is signed with your webhook secret — verify the signature before trusting the payload.

    \    "
  contact:
    name: Sprinklenet Developer Support
    email: hello@sprinklenet.com
    url: https://sprinklenet.com/developers/
  license:
    name: Proprietary — © Sprinklenet
    url: https://sprinklenet.com/terms/
  termsOfService: https://sprinklenet.com/terms/
servers:
  - url: https://spaces.sprinklenet.com/api
    description: Production
  - url: http://localhost:3000/api
    description: Local development
security:
  - ApiKeyAuth: []
  - BearerApiKey: []
tags:
  - name: Chat
    description: Send messages to a bot and read conversation transcripts.
  - name: Sessions
    description: Create, inspect, update, and end conversation sessions (GDPR-ready).
  - name: Webhooks
    description: Subscribe to real-time conversation and session events.
  - name: API Keys
    description: Programmatically manage scoped developer API keys (available when scoped keys are enabled for your organization).
  - name: Rate Limits
    description: Inspect the public rate-limit policy.
x-tagGroups:
  - name: Conversations
    tags:
      - Chat
      - Sessions
  - name: Platform
    tags:
      - Webhooks
      - API Keys
      - Rate Limits
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: Organization API key (`ks_live_…`) generated in Console → Settings → API Keys.
    BearerApiKey:
      type: http
      scheme: bearer
      bearerFormat: ks_live_…
      description: "Same organization API key, sent as `Authorization: Bearer ks_live_…`."
  parameters:
    BotId:
      name: bot_id
      in: path
      required: true
      description: Identifier of the target bot.
      schema:
        type: string
        example: 665f1a2b3c4d5e6f7a8b9c0d
    SessionId:
      name: session_id
      in: path
      required: true
      description: Caller-defined conversation identifier.
      schema:
        type: string
        example: support-thread-123
    OrgId:
      name: org_id
      in: path
      required: true
      description: Your organization identifier.
      schema:
        type: string
        example: 6650aa11bb22cc33dd44ee55
    PageParam:
      name: page
      in: query
      required: false
      description: 1-based page number.
      schema:
        type: integer
        minimum: 1
        default: 1
    LimitParam:
      name: limit
      in: query
      required: false
      description: Items per page (max 100).
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 20
  headers:
    RateLimitLimit:
      description: Request quota for the current window.
      schema:
        type: integer
    RateLimitRemaining:
      description: Requests remaining in the current window.
      schema:
        type: integer
    RateLimitReset:
      description: Unix epoch seconds when the window resets.
      schema:
        type: integer
    RetryAfter:
      description: Seconds to wait before retrying (present on 429).
      schema:
        type: integer
  schemas:
    Error:
      type: object
      required:
        - success
        - message
      properties:
        success:
          type: boolean
          example: false
        message:
          type: string
          description: Human-readable error explanation.
          example: Invalid API key
        code:
          type: string
          description: Stable, machine-readable error code for programmatic handling.
          example: invalid_api_key
    Success:
      type: object
      required:
        - success
      properties:
        success:
          type: boolean
          example: true
        message:
          type: string
          example: Operation completed successfully
    Pagination:
      type: object
      description: Pagination metadata returned alongside list responses.
      properties:
        page:
          type: integer
          example: 1
        limit:
          type: integer
          example: 20
        total:
          type: integer
          example: 137
        total_pages:
          type: integer
          example: 7
    ChatRequest:
      type: object
      required:
        - session_id
        - text
      properties:
        session_id:
          type: string
          description: Caller-controlled conversation id. Reuse the same value to continue a thread; use a new value to start a fresh conversation.
          example: support-thread-123
        text:
          type: string
          maxLength: 50000
          description: The user message to send to the bot.
          example: Summarize the newest source memo.
        context:
          type: object
          additionalProperties: true
          description: Optional structured context merged into this turn.
          example:
            user_tier: pilot
            locale: en-US
        stream:
          type: boolean
          default: false
          description: When `true`, the response is a `text/event-stream` of Server-Sent Events instead of a single JSON object.
    ChatResponse:
      type: object
      required:
        - success
        - text
      properties:
        success:
          type: boolean
          example: true
        text:
          description: The bot's reply. Usually a string; structured replies return an object.
          oneOf:
            - type: string
            - type: object
              additionalProperties: true
          example: The newest memo covers Q3 pricing changes and the new refund policy.
    ChatMessage:
      type: object
      properties:
        role:
          type: string
          enum:
            - user
            - assistant
          example: assistant
        content:
          type: string
          example: How can I help you today?
        timestamp:
          type: string
          format: date-time
    ChatHistoryResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        messages:
          type: array
          items:
            $ref: "#/components/schemas/ChatMessage"
    Session:
      type: object
      properties:
        session_id:
          type: string
          example: support-thread-123
        chatbot_id:
          type: string
          example: 665f1a2b3c4d5e6f7a8b9c0d
        created_at:
          type: string
          format: date-time
        last_active_at:
          type: string
          format: date-time
        message_count:
          type: integer
          example: 8
        end_user_id:
          type: string
          nullable: true
          description: Your identifier for the end user in this conversation.
          example: user_42
        custom_context:
          type: object
          additionalProperties: true
        status:
          type: string
          enum:
            - active
            - ended
          example: active
    SessionEnvelope:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          $ref: "#/components/schemas/Session"
    SessionContextUpdate:
      type: object
      description: Fields to merge into the session's stored context.
      properties:
        custom_context:
          type: object
          additionalProperties: true
          example:
            plan: enterprise
            region: eu
        end_user_id:
          type: string
          example: user_42
    WebhookEventType:
      type: string
      description: A subscribable event. Wildcards (`bot.*`, `session.*`, `*`) are supported.
      enum:
        - bot.conversation_started
        - bot.conversation_ended
        - session.created
        - session.ended
        - escalation.fired
        - bot.*
        - session.*
        - escalation.*
        - "*"
    Webhook:
      type: object
      properties:
        _id:
          type: string
        org_id:
          type: string
        name:
          type: string
          maxLength: 100
          example: Ops alerting
        url:
          type: string
          format: uri
          maxLength: 2048
          example: https://example.com/hooks/knowledge-spaces
        events:
          type: array
          items:
            $ref: "#/components/schemas/WebhookEventType"
          example:
            - session.ended
            - escalation.fired
        enabled:
          type: boolean
          default: true
        bot_ids:
          type: array
          items:
            type: string
          description: Optional filter. Empty means all bots in the organization.
        retry_count:
          type: integer
          minimum: 0
          maximum: 10
          default: 3
        timeout_ms:
          type: integer
          minimum: 1000
          maximum: 30000
          default: 10000
        last_triggered_at:
          type: string
          format: date-time
          nullable: true
        last_success_at:
          type: string
          format: date-time
          nullable: true
        last_failure_at:
          type: string
          format: date-time
          nullable: true
        failure_count:
          type: integer
          example: 0
        auto_disabled:
          type: boolean
          default: false
        createdAt:
          type: string
          format: date-time
    CreateWebhook:
      type: object
      required:
        - name
        - url
        - events
      properties:
        name:
          type: string
          maxLength: 100
          example: Ops alerting
        url:
          type: string
          format: uri
          maxLength: 2048
          example: https://example.com/hooks/knowledge-spaces
        events:
          type: array
          minItems: 1
          items:
            $ref: "#/components/schemas/WebhookEventType"
          example:
            - session.ended
        enabled:
          type: boolean
          default: true
        bot_ids:
          type: array
          items:
            type: string
        retry_count:
          type: integer
          minimum: 0
          maximum: 10
          default: 3
        timeout_ms:
          type: integer
          minimum: 1000
          maximum: 30000
          default: 10000
        custom_headers:
          type: object
          additionalProperties:
            type: string
          description: Extra headers sent with each delivery.
    WebhookDelivery:
      type: object
      properties:
        _id:
          type: string
        webhook_id:
          type: string
        event_type:
          $ref: "#/components/schemas/WebhookEventType"
        url:
          type: string
          format: uri
        status:
          type: string
          enum:
            - pending
            - success
            - failed
            - retrying
        http_status:
          type: integer
          nullable: true
          example: 200
        error_message:
          type: string
          nullable: true
        latency_ms:
          type: integer
          nullable: true
        attempt_number:
          type: integer
          example: 1
        next_retry_at:
          type: string
          format: date-time
          nullable: true
        createdAt:
          type: string
          format: date-time
    ApiKeyScope:
      type: string
      description: A permission granted to a scoped API key.
      enum:
        - bots:read
        - bots:chat
        - bots:write
        - sessions:read
        - sessions:write
        - documents:read
        - documents:write
        - spaces:read
        - spaces:write
        - webhooks:read
        - webhooks:write
        - analytics:read
        - admin
    ApiKey:
      type: object
      description: A scoped developer API key. The raw secret is only ever returned at creation.
      properties:
        _id:
          type: string
        name:
          type: string
          maxLength: 100
          example: CI integration
        description:
          type: string
          maxLength: 500
        key_prefix:
          type: string
          description: First 12 characters of the key, e.g. `ks_live_a1b2`. Safe to display.
          example: ks_live_a1b2
        scopes:
          type: array
          items:
            $ref: "#/components/schemas/ApiKeyScope"
          example:
            - bots:chat
            - sessions:read
        allowed_bot_ids:
          type: array
          items:
            type: string
          description: Empty means the key may access all bots.
        ip_whitelist:
          type: array
          items:
            type: string
          description: Empty means the key may be used from any IP.
        rate_limits:
          type: object
          properties:
            requests_per_minute:
              type: integer
              default: 60
            requests_per_hour:
              type: integer
              default: 1000
            requests_per_day:
              type: integer
              default: 10000
        is_active:
          type: boolean
          example: true
        expires_at:
          type: string
          format: date-time
          nullable: true
        last_used_at:
          type: string
          format: date-time
          nullable: true
        usage_count:
          type: integer
          example: 1420
        created_at:
          type: string
          format: date-time
    CreateApiKey:
      type: object
      required:
        - name
        - scopes
      properties:
        name:
          type: string
          maxLength: 100
          example: CI integration
        description:
          type: string
          maxLength: 500
        scopes:
          type: array
          minItems: 1
          items:
            $ref: "#/components/schemas/ApiKeyScope"
          example:
            - bots:chat
            - sessions:read
        allowed_bot_ids:
          type: array
          items:
            type: string
        ip_whitelist:
          type: array
          items:
            type: string
        expires_at:
          type: string
          format: date-time
          nullable: true
          description: When the key should stop working. Null means it never expires.
    CreateApiKeyResponse:
      type: object
      description: Returned once, at creation. `key` is the full secret and is never shown again — store it now.
      properties:
        success:
          type: boolean
          example: true
        key:
          type: string
          description: The full API key secret. Shown only once.
          example: ks_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
        data:
          $ref: "#/components/schemas/ApiKey"
  responses:
    BadRequest:
      description: The request was malformed or missing required fields.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Unauthorized:
      description: Missing or invalid API key.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          example:
            success: false
            message: Invalid API key
            code: invalid_api_key
    PaymentRequired:
      description: Organization usage limit reached.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Forbidden:
      description: The API key does not have access to this resource or scope.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    NotFound:
      description: The requested resource does not exist.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    TooManyRequests:
      description: Rate limit exceeded. Inspect the `Retry-After` header before retrying.
      headers:
        Retry-After:
          $ref: "#/components/headers/RetryAfter"
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
paths:
  /bots/{bot_id}/chat:
    post:
      tags:
        - Chat
      summary: Send a message to a bot
      operationId: sendChatMessage
      description: "Sends a user message to a bot and returns its reply. Reuse a `session_id` to continue a conversation. Set `stream: true` to receive a Server-Sent Event stream."
      parameters:
        - $ref: "#/components/parameters/BotId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ChatRequest"
            examples:
              basic:
                summary: Simple message
                value:
                  session_id: support-thread-123
                  text: What should I read first?
              withContext:
                summary: Message with context
                value:
                  session_id: support-thread-123
                  text: Recommend next steps.
                  context:
                    user_tier: enterprise
              streaming:
                summary: Streamed response
                value:
                  session_id: support-thread-123
                  text: Draft a long summary.
                  stream: true
      responses:
        "200":
          description: "The bot's reply. A JSON object, or an SSE stream when `stream: true`."
          headers:
            RateLimit-Remaining:
              $ref: "#/components/headers/RateLimitRemaining"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ChatResponse"
            text/event-stream:
              schema:
                type: string
                description: Server-Sent Events; one token/chunk per event.
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "402":
          $ref: "#/components/responses/PaymentRequired"
        "403":
          $ref: "#/components/responses/Forbidden"
        "429":
          $ref: "#/components/responses/TooManyRequests"
    get:
      tags:
        - Chat
      summary: Get chat history for a session
      operationId: getChatHistory
      description: Returns the message transcript for a conversation session.
      parameters:
        - $ref: "#/components/parameters/BotId"
        - name: session_id
          in: query
          required: true
          description: The conversation to fetch the transcript for.
          schema:
            type: string
            example: support-thread-123
      responses:
        "200":
          description: Chat transcript.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ChatHistoryResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /sessions/{session_id}:
    get:
      tags:
        - Sessions
      summary: Get session details
      operationId: getSession
      parameters:
        - $ref: "#/components/parameters/SessionId"
      responses:
        "200":
          description: Session details.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SessionEnvelope"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
    delete:
      tags:
        - Sessions
      summary: Delete a session
      operationId: deleteSession
      description: Permanently deletes the session and all of its messages. Use this to satisfy data-retention or GDPR erasure requests.
      parameters:
        - $ref: "#/components/parameters/SessionId"
      responses:
        "200":
          description: Session deleted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Success"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
  /sessions/{session_id}/context:
    put:
      tags:
        - Sessions
      summary: Update session context
      operationId: updateSessionContext
      description: Merges the supplied fields into the session's stored context.
      parameters:
        - $ref: "#/components/parameters/SessionId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/SessionContextUpdate"
            example:
              custom_context:
                plan: enterprise
              end_user_id: user_42
      responses:
        "200":
          description: Session context updated.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SessionEnvelope"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
  /sessions/{session_id}/end:
    post:
      tags:
        - Sessions
      summary: End a session
      operationId: endSession
      description: Marks a session as ended. The transcript is retained; no further messages can be sent on it.
      parameters:
        - $ref: "#/components/parameters/SessionId"
      responses:
        "200":
          description: Session ended.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Success"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
  /webhooks/events:
    get:
      tags:
        - Webhooks
      summary: List subscribable event types
      operationId: listWebhookEvents
      description: Returns the catalog of events you can subscribe a webhook to.
      responses:
        "200":
          description: Event catalog.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/WebhookEventType"
        "401":
          $ref: "#/components/responses/Unauthorized"
  /orgs/{org_id}/webhooks:
    get:
      tags:
        - Webhooks
      summary: List webhooks
      operationId: listWebhooks
      parameters:
        - $ref: "#/components/parameters/OrgId"
      responses:
        "200":
          description: Webhooks for the organization.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/Webhook"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
    post:
      tags:
        - Webhooks
      summary: Create a webhook
      operationId: createWebhook
      parameters:
        - $ref: "#/components/parameters/OrgId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateWebhook"
            example:
              name: Ops alerting
              url: https://example.com/hooks/knowledge-spaces
              events:
                - session.ended
                - escalation.fired
      responses:
        "201":
          description: Webhook created.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    $ref: "#/components/schemas/Webhook"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
  /orgs/{org_id}/webhooks/{webhook_id}:
    get:
      tags:
        - Webhooks
      summary: Get a webhook
      operationId: getWebhook
      parameters:
        - $ref: "#/components/parameters/OrgId"
        - name: webhook_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Webhook details.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    $ref: "#/components/schemas/Webhook"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
    put:
      tags:
        - Webhooks
      summary: Update a webhook
      operationId: updateWebhook
      parameters:
        - $ref: "#/components/parameters/OrgId"
        - name: webhook_id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateWebhook"
      responses:
        "200":
          description: Webhook updated.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    $ref: "#/components/schemas/Webhook"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
    delete:
      tags:
        - Webhooks
      summary: Delete a webhook
      operationId: deleteWebhook
      parameters:
        - $ref: "#/components/parameters/OrgId"
        - name: webhook_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Webhook deleted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Success"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
  /orgs/{org_id}/webhooks/{webhook_id}/deliveries:
    get:
      tags:
        - Webhooks
      summary: List webhook deliveries
      operationId: listWebhookDeliveries
      description: Recent delivery attempts for a webhook, for debugging failures.
      parameters:
        - $ref: "#/components/parameters/OrgId"
        - name: webhook_id
          in: path
          required: true
          schema:
            type: string
        - $ref: "#/components/parameters/PageParam"
        - $ref: "#/components/parameters/LimitParam"
      responses:
        "200":
          description: Delivery history.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/WebhookDelivery"
                  pagination:
                    $ref: "#/components/schemas/Pagination"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
  /orgs/{org_id}/webhooks/{webhook_id}/test:
    post:
      tags:
        - Webhooks
      summary: Send a test event
      operationId: testWebhook
      description: Delivers a sample payload to the webhook URL so you can verify your receiver.
      parameters:
        - $ref: "#/components/parameters/OrgId"
        - name: webhook_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Test delivery attempted.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    $ref: "#/components/schemas/WebhookDelivery"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
  /api-keys/scopes:
    get:
      tags:
        - API Keys
      summary: List available scopes
      operationId: listApiKeyScopes
      description: Returns every scope that can be granted to a developer API key. Available when scoped API keys are enabled for your organization.
      responses:
        "200":
          description: Available scopes.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/ApiKeyScope"
        "401":
          $ref: "#/components/responses/Unauthorized"
  /orgs/{org_id}/api-keys:
    get:
      tags:
        - API Keys
      summary: List API keys
      operationId: listApiKeys
      description: Lists scoped API keys for the organization. Secrets are never returned.
      parameters:
        - $ref: "#/components/parameters/OrgId"
      responses:
        "200":
          description: API keys.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/ApiKey"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
    post:
      tags:
        - API Keys
      summary: Create an API key
      operationId: createApiKey
      description: Creates a scoped API key. The full secret is returned **once** in this response and cannot be retrieved again.
      parameters:
        - $ref: "#/components/parameters/OrgId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateApiKey"
            example:
              name: CI integration
              scopes:
                - bots:chat
                - sessions:read
              expires_at: null
      responses:
        "201":
          description: API key created. Store the returned secret now — it will not be shown again.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CreateApiKeyResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
  /orgs/{org_id}/api-keys/{key_id}/revoke:
    post:
      tags:
        - API Keys
      summary: Revoke an API key
      operationId: revokeApiKey
      description: Immediately and permanently disables an API key.
      parameters:
        - $ref: "#/components/parameters/OrgId"
        - name: key_id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: API key revoked.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Success"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
  /rate-limit/info:
    get:
      tags:
        - Rate Limits
      summary: Get the public rate-limit policy
      operationId: getRateLimitInfo
      description: Returns the current public rate-limit policy. No authentication required.
      security: []
      responses:
        "200":
          description: Rate-limit policy metadata.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: object
                    additionalProperties: true
