openapi: 3.0.3
info:
  title: FluentC API
  version: 1.0.0
  description: |
    Translate text, HTML and JSON in real-time or batch mode, detect languages, and list the languages enabled for your API key. FluentC is built for agents and workflows that call translation thousands of times an hour.

    Documentation: https://www.fluentc.ai/docs/ (every page also at https://www.fluentc.ai/docs/<page>.md; index at https://www.fluentc.ai/llms.txt)

    ## Authentication
    Send your API key in the `Authorization` header exactly as the dashboard shows it. Do not add a `Bearer` prefix: `Bearer <key>` is read as a different, unknown key and returns 401.

    ## Modes
    - `real-time` returns the translation in the response. It needs the Real-time plan.
    - `batch` returns a `job_id`. Poll `POST /ai_agent/results` until `status` is `complete`. Available on the Batch and Real-time plans.

    ## Language codes
    Lowercase ISO 639-1 or 639-2 codes of two or three letters, such as `es`, `fr`, `ja`. Region subtags (`pt-BR`) are not accepted. A code must be enabled for your key; list them with `GET /ai_agent/languages`.
  contact:
    name: FluentC
    url: https://www.fluentc.ai/contact/

servers:
  - url: https://api.fluentc.ai
    description: Production

security:
  - ApiKeyAuth: []

tags:
  - name: Translation
    description: Translate text, HTML and JSON.
  - name: Results
    description: Fetch the result of a batch job.
  - name: Language detection
    description: Identify the language of some content.
  - name: Languages
    description: Languages enabled for your key.

paths:
  /ai_agent/translate:
    post:
      tags: [Translation]
      operationId: translate
      summary: Translate
      description: |
        Translates `input` into `target_language`. In `real-time` mode the translation is in the response. In `batch` mode the response is a `job_id` for `POST /ai_agent/results`.

        The `job_id` is deterministic for the same `input` and `target_language`, so resubmitting is safe. Identical input is answered from translation memory.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TranslateRequest"
            examples:
              realTimeText:
                summary: Real-time text
                value:
                  input: "Hello, world!"
                  input_format: text
                  target_language: es
                  source_language: en
                  mode: real-time
              batchHtml:
                summary: Batch HTML
                value:
                  input: "<h1>Welcome</h1><p>This is a sample page.</p>"
                  input_format: html
                  target_language: fr
                  mode: batch
              batchJson:
                summary: Batch JSON
                value:
                  input:
                    title: Welcome
                    cta: Start now
                  input_format: json
                  target_language: ja
                  mode: batch
      responses:
        "200":
          description: Real-time translation, or an accepted batch job.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/Translation"
                  - $ref: "#/components/schemas/BatchJob"
              examples:
                realTime:
                  summary: Real-time
                  value:
                    status: complete
                    translation: "¡Hola, mundo!"
                    token_count: 15
                    source_language_detected: en
                batch:
                  summary: Batch accepted
                  value:
                    job_id: abc123def456
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "422":
          $ref: "#/components/responses/Invalid"
        "500":
          $ref: "#/components/responses/ServerError"

  /ai_agent/results:
    post:
      tags: [Results]
      operationId: getResults
      summary: Batch results
      description: |
        Returns the state of a batch job. The HTTP status is 200 for all three states; read `status`.

        A `job_id` the API has never seen is reported as `processing`, not as an error, so cap the number of polls.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [job_id]
              properties:
                job_id:
                  type: string
                  description: The `job_id` returned by a batch translate request.
                  example: abc123def456
      responses:
        "200":
          description: The job's current state.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/Translation"
                  - $ref: "#/components/schemas/Processing"
                  - $ref: "#/components/schemas/Failed"
              examples:
                complete:
                  summary: Complete
                  value:
                    status: complete
                    translation: "<h1>Bienvenue</h1><p>Ceci est un exemple de page.</p>"
                    token_count: 31
                    source_language_detected: en
                processing:
                  summary: Processing
                  value:
                    status: processing
                    estimated_wait_seconds: 5
                    next_poll_after: "2026-01-15T10:30:00Z"
                failed:
                  summary: Failed
                  value:
                    status: failed
                    error: "Translation failed for the given job_id; content was recognized but the translation is unavailable."
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "422":
          $ref: "#/components/responses/Invalid"
        "500":
          $ref: "#/components/responses/ServerError"

  /ai_agent/checklanguage:
    post:
      tags: [Language detection]
      operationId: detectLanguage
      summary: Detect language
      description: Identifies the language of text or HTML and reports a confidence score.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [input, input_format]
              properties:
                input:
                  type: string
                  description: The text or HTML to analyse.
                  example: "Bonjour, comment allez-vous?"
                input_format:
                  type: string
                  enum: [text, html]
                  description: JSON is not accepted.
      responses:
        "200":
          description: The detected language.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Detection"
              example:
                detected_language: fr
                confidence: 0.99
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "422":
          $ref: "#/components/responses/Invalid"
        "500":
          $ref: "#/components/responses/ServerError"

  /ai_agent/languages:
    get:
      tags: [Languages]
      operationId: listLanguages
      summary: Languages
      description: Lists the languages enabled for your key. A language must appear here before it can be used as `target_language` or `source_language`.
      responses:
        "200":
          description: The enabled languages.
          content:
            application/json:
              schema:
                type: object
                required: [supported_languages, source_languages]
                properties:
                  supported_languages:
                    type: array
                    description: Languages you can translate into.
                    items:
                      $ref: "#/components/schemas/Language"
                  source_languages:
                    type: array
                    description: Languages you can name as `source_language`.
                    items:
                      $ref: "#/components/schemas/Language"
              example:
                supported_languages:
                  - { code: es, name: Spanish }
                  - { code: fr, name: French }
                source_languages:
                  - { code: en, name: English }
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "500":
          $ref: "#/components/responses/ServerError"

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: Your FluentC API key, sent as-is. No `Bearer` prefix.

  schemas:
    TranslateRequest:
      type: object
      required: [input, input_format, target_language, mode]
      properties:
        input:
          description: The content to translate. A JSON object is accepted when `input_format` is `json`.
          oneOf:
            - type: string
            - type: object
        input_format:
          type: string
          enum: [text, html, json]
          description: "`html` keeps markup and translates the text inside it. `json` keeps structure and translates string values."
        target_language:
          $ref: "#/components/schemas/LanguageCode"
        source_language:
          allOf:
            - $ref: "#/components/schemas/LanguageCode"
          description: Language of `input`. If omitted, it is worked out from the text.
        mode:
          type: string
          enum: [real-time, batch]
          description: Case-insensitive. `real-time` needs the Real-time plan.

    LanguageCode:
      type: string
      pattern: "^[a-zA-Z]{2,3}$"
      description: Two- or three-letter ISO 639 code. Lowercased by the API. Must be enabled for your key.
      example: es

    Translation:
      type: object
      required: [status, translation, token_count, source_language_detected]
      properties:
        status:
          type: string
          enum: [complete]
        translation:
          type: string
          description: The translated content. For `json` input it is a JSON-encoded string; parse it.
        token_count:
          type: integer
          description: The size of the translation in tokens.
        source_language_detected:
          type: string
          description: The source language code, detected or as sent.

    BatchJob:
      type: object
      required: [job_id]
      properties:
        job_id:
          type: string
          description: Identifies the batch job. Deterministic for the same input and target language.

    Processing:
      type: object
      required: [status, estimated_wait_seconds, next_poll_after]
      properties:
        status:
          type: string
          enum: [processing]
        estimated_wait_seconds:
          type: integer
          description: Wait at least this long (and no less than 5 seconds) before polling again.
        next_poll_after:
          type: string
          format: date-time

    Failed:
      type: object
      required: [status, error]
      properties:
        status:
          type: string
          enum: [failed]
        error:
          type: string

    Detection:
      type: object
      required: [detected_language, confidence]
      properties:
        detected_language:
          type: string
          description: The language code, in the same format as `target_language`.
        confidence:
          type: number
          minimum: 0
          maximum: 1

    Language:
      type: object
      required: [code, name]
      properties:
        code:
          type: string
          example: es
        name:
          type: string
          description: The language's name in English.
          example: Spanish

    Error:
      type: object
      required: [error]
      properties:
        error:
          type: string

  responses:
    Unauthorized:
      description: The key is missing or wrong.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          examples:
            missing:
              value: { error: "API key (Site UUID) is missing" }
            invalid:
              value: { error: "Invalid API key: Site not found." }
    Forbidden:
      description: The key is valid but the account can't make this request (translation disabled, inactive subscription, or a usage limit).
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          examples:
            disabled:
              value: { error: "Access denied: Translations are disabled for this site." }
            subscription:
              value: { error: "Subscription error: Company subscription is not active" }
            usage:
              value: { error: "Usage limit error: Free tier limit exceeded" }
    Invalid:
      description: The request is invalid. The message names the problem.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
          examples:
            input:
              value: { error: "Input is missing" }
            format:
              value: { error: "Invalid or missing input format. Allowed formats: text, html, json" }
            language:
              value: { error: "Invalid or missing target language code." }
            notEnabled:
              value: { error: "Target language 'es' is not enabled for this site." }
            mode:
              value: { error: "Invalid or missing mode. Allowed modes: batch, real-time" }
            plan:
              value: { error: "Realtime translation is not supported for this agent." }
            job:
              value: { error: "job_id (hash_key) is missing" }
    ServerError:
      description: Something went wrong on our side. Retry with backoff.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
