openapi: 3.0.3
info:
  title: Athena RS
  version: 0.80.2
  description: Athena gateway API and driver
servers:
- url: https://athena-db.com
paths:
  /:
    get:
      summary: API root and route listing
      description: Returns health status and a list of all available routes with methods and summaries (PostgREST-style).
      responses:
        "200":
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: athena is online
                  version:
                    type: string
                    description: API version (cargo_toml_version)
                  athena_api:
                    type: string
                    example: online
                  athena_deadpool:
                    type: string
                    example: online
                  athena_scylladb:
                    type: string
                    enum: [ online, offline ]
                  cargo_toml_version:
                    type: string
                  routes:
                    type: array
                    description: All available routes with path, methods, and summary
                    items:
                      type: object
                      properties:
                        path:
                          type: string
                          example: /gateway/data
                        methods:
                          type: array
                          items: { type: string }
                          example: [ "POST" ]
                        summary:
                          type: string
  /query/sql:
    post:
      summary: Execute SQL using selected driver
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                query:
                  type: string
                driver:
                  type: string
                  enum: [ athena, postgresql, supabase ]
                db_name:
                  type: string
              required: [ query, driver, db_name ]
      responses:
        "200":
          description: Query executed
          content:
            application/json:
              schema:
                type: object
        "400":
          description: Invalid driver
        "500":
          description: Driver execution failed
        "503":
          description: Athena/Scylla unavailable
  /gateway/fetch:
    post:
      summary: Fetch data with conditions
      parameters:
      - in: header
        name: X-User-Id
        schema: { type: string }
      - in: header
        name: X-Athena-Client
        schema: { type: string }
      - in: header
        name: X-Strip-Nulls
        schema: { type: string }
      - in: header
        name: apikey
        schema: { type: string }
      - in: header
        name: x-api-key
        description: optional API key mirror of the `apikey` header
        schema: { type: string }
      - in: header
        name: x-supabase-url
        description: Required when X-Athena-Client is custom_supabase
        schema: { type: string, format: uri }
      - in: header
        name: x-supabase-key
        description: Required when X-Athena-Client is custom_supabase
        schema: { type: string }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                view_name:
                  type: string
                table_name:
                  type: string
                columns:
                  oneOf:
                  - type: array
                    items: { type: string }
                  - type: string
                conditions:
                  type: array
                  items:
                    type: object
                    properties:
                      eq_column: { type: string }
                      eq_value: { type: string }
                limit: { type: integer }
                current_page: { type: integer }
                page_size: { type: integer }
                offset: { type: integer }
                total_pages: { type: integer }
                strip_nulls: { type: boolean }
                group_by:
                  type: string
                  description: Column name to group results by
                time_granularity:
                  type: string
                  enum: [ day, hour, minute ]
                  description: Time granularity for grouping timestamp data
                aggregation_column:
                  type: string
                  description: Column to aggregate (required when using aggregation_strategy)
                aggregation_strategy:
                  type: string
                  enum: [ cumulative_sum ]
                  description: Aggregation strategy to apply (requires aggregation_column)
                aggregation_dedup:
                  type: boolean
                  description: Whether to deduplicate during aggregation
              required: [ conditions ]
      responses:
        "200": { description: OK }
        "400": { description: Bad request }
        "500": { description: Internal error }
  /data:
    get:
      summary: Fetch data via GET
      parameters:
      - in: query
        name: view
        required: true
        schema: { type: string }
      - in: query
        name: eq_column
        required: true
        schema: { type: string }
      - in: query
        name: eq_value
        required: true
        schema: { type: string }
      - in: query
        name: columns
        schema: { type: string }
      - in: query
        name: limit
        schema: { type: integer }
      - in: query
        name: current_page
        schema: { type: integer }
      - in: query
        name: page_size
        schema: { type: integer }
      - in: query
        name: offset
        schema: { type: integer }
      - in: query
        name: total_pages
        schema: { type: integer }
      - in: query
        name: strip_nulls
        schema: { type: boolean }
      - in: query
        name: group_by
        schema: { type: string }
        description: Column name to group results by
      - in: query
        name: time_granularity
        schema:
          type: string
          enum: [ day, hour, minute ]
        description: Time granularity for grouping timestamp data
      - in: query
        name: aggregation_column
        schema: { type: string }
        description: Column to aggregate (required when using aggregation_strategy)
      - in: query
        name: aggregation_strategy
        schema:
          type: string
          enum: [ cumulative_sum ]
        description: Aggregation strategy to apply (requires aggregation_column)
      - in: query
        name: aggregation_dedup
        schema: { type: boolean }
        description: Whether to deduplicate during aggregation
      - in: header
        name: X-User-Id
        schema: { type: string }
      - in: header
        name: X-Athena-Client
        schema: { type: string }
      - in: header
        name: X-Strip-Nulls
        schema: { type: string }
      - in: header
        name: apikey
        schema: { type: string }
      - in: header
        name: x-api-key
        description: optional API key mirror of the `apikey` header
        schema: { type: string }
      - in: header
        name: x-supabase-url
        description: Optional custom Supabase URL when X-Athena-Client is custom_supabase
        schema: { type: string, format: uri }
      - in: header
        name: x-supabase-key
        description: Optional custom Supabase key when X-Athena-Client is custom_supabase
        schema: { type: string }
      responses:
        "200": { description: OK }
        "400": { description: Bad request }
        "500": { description: Internal error }
  /gateway/insert:
    put:
      summary: Insert a row into a table
      parameters:
      - in: header
        name: X-User-Id
        required: true
        schema: { type: string }
      - in: header
        name: X-Company-Id
        required: true
        schema: { type: string }
      - in: header
        name: X-Organization-Id
        required: true
        schema: { type: string }
      - in: header
        name: X-Publish-Event
        schema: { type: string }
      - in: header
        name: X-Athena-Client
        schema: { type: string }
      - in: header
        name: apikey
        schema: { type: string }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                table_name: { type: string }
                insert_body: { type: object }
                update_body: { type: object }
              required: [ table_name, insert_body ]
      responses:
        "200": { description: Inserted }
        "400": { description: Bad request }
        "409": { description: Conflict }
        "500": { description: Internal error }
  /gateway/delete:
    delete:
      summary: Delete a row by id
      parameters:
      - in: header
        name: X-User-Id
        required: true
        schema: { type: string }
      - in: header
        name: X-Company-Id
        required: true
        schema: { type: string }
      - in: header
        name: X-Organization-Id
        required: true
        schema: { type: string }
      - in: header
        name: X-Athena-Client
        schema: { type: string }
      - in: header
        name: apikey
        schema: { type: string }
      - in: header
        name: x-supabase-url
        description: Optional custom Supabase URL when X-Athena-Client is custom_supabase
        schema: { type: string, format: uri }
      - in: header
        name: x-supabase-key
        description: Optional custom Supabase key when X-Athena-Client is custom_supabase
        schema: { type: string }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                table_name: { type: string }
                resource_id: { type: string }
              required: [ table_name, resource_id ]
      responses:
        "200": { description: Deleted }
        "400": { description: Bad request }
        "500": { description: Internal error }
  /gateway/update:
    post:
      summary: Fetch or update data using a SQLx client (same payload as /gateway/fetch)
      parameters:
      - in: header
        name: X-User-Id
        schema: { type: string }
      - in: header
        name: X-Athena-Client
        description: selects which PostgreSQL pool to use
        schema: { type: string }
      - in: header
        name: X-Strip-Nulls
        schema: { type: string }
      - in: header
        name: apikey
        schema: { type: string }
      - in: header
        name: x-api-key
        description: optional API key mirror of the `apikey` header
        schema: { type: string }
      - in: header
        name: x-supabase-url
        description: Required when X-Athena-Client is custom_supabase
        schema: { type: string, format: uri }
      - in: header
        name: x-supabase-key
        description: Required when X-Athena-Client is custom_supabase
        schema: { type: string }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                view_name:
                  type: string
                table_name:
                  type: string
                columns:
                  oneOf:
                  - type: array
                    items: { type: string }
                  - type: string
                conditions:
                  type: array
                  items:
                    type: object
                    properties:
                      eq_column: { type: string }
                      eq_value: { type: string }
                limit: { type: integer }
                current_page: { type: integer }
                page_size: { type: integer }
                offset: { type: integer }
                total_pages: { type: integer }
                strip_nulls: { type: boolean }
                group_by:
                  type: string
                  description: Column name to group results by
                time_granularity:
                  type: string
                  enum: [ day, hour, minute ]
                  description: Time granularity for grouping timestamp data
                aggregation_column:
                  type: string
                  description: Column to aggregate (required when using aggregation_strategy)
                aggregation_strategy:
                  type: string
                  enum: [ cumulative_sum ]
                  description: Aggregation strategy to apply (requires aggregation_column)
                aggregation_dedup:
                  type: boolean
                  description: Whether to deduplicate during aggregation
              required: [ conditions ]
      responses:
        "200": { description: OK }
        "400": { description: Bad request }
        "500": { description: Internal error }
  /gateway/query:
    post:
      summary: Run a raw SQL query against the selected PostgreSQL pool
      parameters:
      - in: header
        name: X-Athena-Client
        description: selects which PostgreSQL pool the SQL executes against
        required: true
        schema: { type: string }
      - in: header
        name: x-api-key
        description: optional API key mirror of the `apikey` header in the body
        schema: { type: string }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                query:
                  description: raw SQL to execute
                  type: string
              required: [ query ]
      responses:
        "200": { description: OK }
        "400": { description: Bad request }
        "500": { description: Internal error }

  /pipelines:
    post:
      summary: Run a config-driven pipeline (source → transform → sink)
      description: Executes a pipeline with optional prebuilt reference and overrides. Uses X-Athena-Client for routing (same as gateway).
      parameters:
      - in: header
        name: X-Athena-Client
        required: true
        schema: { type: string }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                pipeline:
                  type: string
                  description: Prebuilt pipeline name from config/pipelines.yaml
                source:
                  type: object
                  properties:
                    table_name: { type: string }
                    view_name: { type: string }
                    columns: { type: array, items: { type: string } }
                    conditions:
                      type: array
                      items:
                        type: object
                        properties:
                          eq_column: { type: string }
                          eq_value: { type: string }
                    limit: { type: integer }
                transform:
                  type: object
                  properties:
                    group_by: { type: string }
                    time_granularity: { type: string, enum: [ day, hour, minute ] }
                    aggregation_column: { type: string }
                    aggregation_strategy: { type: string, enum: [ cumulative_sum ] }
                    aggregation_dedup: { type: boolean }
                sink:
                  type: object
                  properties:
                    table_name: { type: string }
      responses:
        "200":
          description: Pipeline run result
          content:
            application/json:
              schema:
                type: object
                properties:
                  data: { type: array, description: Inserted rows }
                  rows_fetched: { type: integer }
                  rows_inserted: { type: integer }
                  errors: { type: array }
        "400": { description: Bad request (e.g. missing X-Athena-Client or unknown pipeline) }
        "500": { description: Internal error }

  /api/v2/supabase/ssl_enforcement:
    post:
      summary: Toggle Supabase SSL enforcement for a project
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                enabled:
                  type: boolean
                  description: Set to true to enable SSL enforcement, false to disable
                access_token:
                  type: string
                  description: Optional override for SUPABASE_ACCESS_TOKEN
                project_ref:
                  type: string
                  description: Optional override for PROJECT_REF
              required:
              - enabled
      responses:
        "200":
          description: SSL enforcement status returned
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: success
                  message:
                    type: string
                  data:
                    type: object
                    properties:
                      currentConfig:
                        type: object
                        properties:
                          database: { type: boolean }
                      appliedSuccessfully:
                        type: boolean
        "400": { description: Missing credentials or bad payload }
        "500": { description: Supabase API error }

  /router/registry:
    get:
      summary: List Athena router registry entries
      responses:
        "200":
          description: An array of router registry objects
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
        "500": { description: Failed to load router registry entries }

  /registry:
    get:
      summary: List API registry entries
      parameters:
      - in: header
        name: Cache-Control
        schema: { type: string }
        description: Set to `no-cache` to skip the cached response.
      responses:
        "200":
          description: API registry rows from Supabase
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
        "500": { description: Failed to list API registry entries }

  /registry/{api_registry_id}:
    get:
      summary: Lookup an API registry entry by ID
      parameters:
      - in: path
        name: api_registry_id
        required: true
        schema: { type: string }
        description: Row identifier from the Supabase table
      - in: header
        name: Cache-Control
        schema: { type: string }
        description: Set to `no-cache` to bypass the cached entry.
      responses:
        "200":
          description: Matching registry entry (wrapped in an array)
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
        "500": { description: Failed to fetch the registry entry }

  /schema/clients:
    get:
      summary: List configured Postgres clients
      responses:
        "200":
          description: A JSON object containing a clients array
          content:
            application/json:
              schema:
                type: object
                properties:
                  clients:
                    type: array
                    items:
                      type: string

  /schema/tables:
    get:
      summary: List tables for the selected Postgres client
      parameters:
      - in: header
        name: X-Athena-Client
        required: true
        schema: { type: string }
        description: Selects which Postgres pool provides the tables.
      responses:
        "200":
          description: Table schema metadata
          content:
            application/json:
              schema:
                type: object
                properties:
                  tables:
                    type: array
                    items:
                      type: object
                      properties:
                        table_schema: { type: string }
                        table_name: { type: string }
        "400": { description: Missing or unknown X-Athena-Client }
        "500": { description: Failed to query information_schema.tables }

  /schema/columns:
    get:
      summary: Describe columns for a given table
      parameters:
      - in: header
        name: X-Athena-Client
        required: true
        schema: { type: string }
      - in: query
        name: table_name
        required: true
        schema: { type: string }
        description: Postgres table name to describe
      responses:
        "200":
          description: Column metadata
          content:
            application/json:
              schema:
                type: object
                properties:
                  columns:
                    type: array
                    items:
                      type: object
                      properties:
                        column_name: { type: string }
                        data_type: { type: string, nullable: true }
                        column_default: { type: string, nullable: true }
                        is_nullable: { type: string, nullable: true }
        "400": { description: Missing header or invalid table_name }
        "500": { description: Failed to fetch column metadata }

  /openapi.yaml:
    get:
      summary: Download the embedded OpenAPI YAML
      responses:
        "200":
          description: OpenAPI spec fixture served by the API
          content:
            application/yaml:
              schema:
                type: string
        "500": { description: Failed to read openapi.yaml }

  /docs:
    get:
      summary: Redirect to the hosted Athena docs
      responses:
        "308":
          description: Permanent redirect to https://xylex.group/docs/athena
          headers:
            Location:
              schema: { type: string, format: uri }
