openapi: 3.0.3
info:
  title: Supervisor Moderation API
  description: |
    AI-powered content moderation. Moderate text and images against 16 content
    labels with three model tiers (Observer, Sentinel, Arbiter), including
    implicit-intent detection and 100+ language support.

    Authenticate with an API key from your dashboard (supervisor.gg/dashboard),
    sent either as a Bearer token or an X-API-Key header.

    Billing: text is billed per byte at the model's rate (Observer 1,
    Sentinel 2, Arbiter 4 credits/byte). Image bytes bill at a flat
    1 credit/byte; text extracted from images by OCR is billed at the model
    rate. Cached (repeat) requests are free.
  version: "1.0"
  contact:
    url: https://supervisor.gg/docs
servers:
  - url: https://supervisor.gg
security:
  - bearerAuth: []
  - apiKeyHeader: []
paths:
  /api/moderate:
    post:
      operationId: moderate
      summary: Moderate text and/or an image
      description: >
        Analyzes the supplied text and/or base64 image and returns which
        labels were triggered. At least one of `text` or `image` is required.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ModerationRequest"
            examples:
              text:
                summary: Text moderation
                value:
                  text: "message to check"
                  model: observer
              image:
                summary: Image moderation
                value:
                  image: "<base64-encoded image>"
                  model: sentinel
      responses:
        "200":
          description: Moderation verdict
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ModerationResponse"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "402": { $ref: "#/components/responses/PaymentRequired" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
  /api/batch:
    post:
      operationId: moderateBatch
      summary: Moderate many items in one request
      description: >
        Moderates each row independently and returns verdicts in input order.
        `images` (when present) must align 1:1 with `texts`; use an empty
        string for text-only rows.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/BatchModerationRequest"
      responses:
        "200":
          description: One verdict per input row, in order
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/ModerationResponse"
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "402": { $ref: "#/components/responses/PaymentRequired" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
  /api/labels:
    get:
      operationId: getLabels
      summary: List content labels
      description: Returns the supported labels with human-readable descriptions.
      responses:
        "200":
          description: Map of label to description
          content:
            application/json:
              schema:
                type: object
                additionalProperties:
                  type: string
        "401": { $ref: "#/components/responses/Unauthorized" }
  /api/username:
    post:
      operationId: checkUsername
      summary: Check a username for policy violations
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [username]
              properties:
                username:
                  type: string
      responses:
        "200":
          description: Username verdict
          content:
            application/json:
              schema:
                type: object
                properties:
                  flagged:
                    type: boolean
                  score:
                    type: number
                    format: float
        "400": { $ref: "#/components/responses/BadRequest" }
        "401": { $ref: "#/components/responses/Unauthorized" }
        "429": { $ref: "#/components/responses/RateLimited" }
        "500": { $ref: "#/components/responses/ServerError" }
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: "Authorization: Bearer <api key>"
    apiKeyHeader:
      type: apiKey
      in: header
      name: X-API-Key
  schemas:
    ModerationModel:
      type: string
      enum: [auto, observer, sentinel, arbiter]
      description: >
        Model tier. `auto` routes to the best tier your plan allows.
        Observer is fastest, Arbiter is most accurate.
    ModerationLabel:
      type: string
      enum:
        - profanity
        - toxicity
        - harassment
        - hate
        - insult
        - sexual
        - sexual/unlawful
        - sexual/explicit
        - sensitive
        - violence
        - self-harm
        - medical
        - spam
        - promotional
        - scam
        - illegal
    ModerationRequest:
      type: object
      properties:
        text:
          type: string
          nullable: true
          description: Text to moderate. Required if `image` is absent.
        image:
          type: string
          nullable: true
          description: >
            Base64-encoded image (data: URI prefix allowed). Required if
            `text` is absent. Requires the image-moderation plan feature.
        model:
          $ref: "#/components/schemas/ModerationModel"
        enabled_labels:
          type: array
          nullable: true
          items:
            $ref: "#/components/schemas/ModerationLabel"
          description: Only check these labels (default = all).
        include_context:
          type: boolean
          default: false
          description: >
            Include context analysis (`needs_context`, `context_labels`).
            Requires a plan with the context feature.
      anyOf:
        - required: [text]
        - required: [image]
    BatchModerationRequest:
      type: object
      required: [texts]
      properties:
        texts:
          type: array
          items:
            type: string
        images:
          type: array
          items:
            type: string
          description: >
            Optional base64 images aligned 1:1 with `texts` (empty string for
            text-only rows).
        model:
          $ref: "#/components/schemas/ModerationModel"
        enabled_labels:
          type: array
          nullable: true
          items:
            $ref: "#/components/schemas/ModerationLabel"
        include_context:
          type: boolean
          default: false
    ModerationResponse:
      type: object
      required: [flagged, labels]
      properties:
        flagged:
          type: boolean
        labels:
          type: array
          items:
            $ref: "#/components/schemas/ModerationLabel"
          description: Labels triggered by explicit content.
        implicit_labels:
          type: array
          nullable: true
          items:
            $ref: "#/components/schemas/ModerationLabel"
          description: >
            Labels triggered by implied (non-explicit) harm. Present only on
            plans with implicit moderation.
        model_version:
          type: string
          nullable: true
          description: Version of the model that produced this verdict.
        needs_context:
          type: boolean
          nullable: true
          description: Present when `include_context` was requested.
        context_labels:
          type: array
          nullable: true
          items:
            $ref: "#/components/schemas/ModerationLabel"
        extracted_text:
          type: string
          nullable: true
          description: >
            Text extracted from the image by OCR, when an image was supplied
            and readable text was found.
    Error:
      type: object
      properties:
        error:
          type: string
        details:
          type: string
  responses:
    BadRequest:
      description: Invalid parameters, or model not available on your plan
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Unauthorized:
      description: Invalid or missing API key
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    PaymentRequired:
      description: Insufficient credits
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    RateLimited:
      description: Usage limit reached for the current 4-hour window
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    ServerError:
      description: Unexpected server error
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
