openapi: 3.0.3
info:
  title: Ghost Legacy Phase 1 API
  version: 1.0.0
  description: |
    Legacy Ghost/VisualPlus HTTP surface preserved for Phase 1 dockerization and Azure Blob-backed storage.
servers:
  - url: /
    description: Current host serving Swagger UI or the OpenAPI spec
components:
  parameters:
    AccessKey:
      in: query
      name: ca
      required: true
      schema:
        type: string
        pattern: '^\d{49}$'
      example: '2002202601110473203500120010020000000021234567818'
paths:
  /fe2/publicar.php:
    post:
      summary: Store XML by access key
      description: Accepts the raw XML body and stores it as a ZIP blob under the derived docs path.
      parameters:
        - $ref: '#/components/parameters/AccessKey'
      requestBody:
        required: true
        content:
          application/xml:
            schema:
              type: string
            example: |
              <autorizacion>
                <numeroAutorizacion>0101202401110473204300110010010000000011234567811</numeroAutorizacion>
                <fechaAutorizacion>2024-01-01T10:00:00-05:00</fechaAutorizacion>
                <comprobante><![CDATA[<factura id="comprobante" version="1.0.0"></factura>]]></comprobante>
              </autorizacion>
      responses:
        '200':
          description: XML accepted by the legacy endpoint.
  /fe2/ghost.php:
    get:
      summary: Render PDF by access key
      description: Streams the generated PDF inline by default. Use `download=1` to force attachment behavior, which works better in Swagger UI.
      parameters:
        - $ref: '#/components/parameters/AccessKey'
        - in: query
          name: ca1
          required: false
          schema:
            type: string
        - in: query
          name: download
          required: false
          schema:
            type: integer
            enum: [1]
            default: 1
          example: 1
          description: "Set to `1` to return `Content-Disposition: attachment` instead of `inline`."
      responses:
        '200':
          description: PDF stream
          content:
            application/pdf:
              schema:
                type: string
                format: binary
      x-codeSamples:
        - lang: curl
          label: Download PDF
          source: |
            curl -OJ "https://your-host.example/fe2/ghost.php?ca=2002202601110473203500120010020000000021234567818&download=1"
  /fe2/descargar.php:
    get:
      summary: Download XML by access key
      description: Requires the legacy time-based token generated for the current server minute. Use `/fe2/get_download_token.php` during local testing.
      parameters:
        - $ref: '#/components/parameters/AccessKey'
        - in: query
          name: token
          required: true
          schema:
            type: string
          example: '8M7I9D9J9E7F'
      responses:
        '200':
          description: XML payload as attachment
          content:
            application/octet-stream:
              schema:
                type: string
                format: binary
        '403':
          description: Invalid or missing token
  /fe2/get_download_token.php:
    get:
      summary: Get current descargar token for testing
      description: Returns the current minute-based token accepted by `descargar.php`. Intended for local validation and Swagger/Postman testing.
      responses:
        '200':
          description: Current token payload
          content:
            application/json:
              schema:
                type: object
                properties:
                  timezone:
                    type: string
                  generated_at:
                    type: string
                    format: date-time
                  base_string:
                    type: string
                  token:
                    type: string
  /fe2/getghost.php:
    get:
      summary: Get emitter Ghost configuration summary
      description: |
        Looks up one emitter in the `bdd` table by RUC and returns a legacy pipe-delimited configuration string.

        This is a metadata/config endpoint, not a PDF/XML document endpoint. It appears to be intended for legacy clients that need to know emitter-level Ghost settings before using other flows.

        Response field order:
        1. `bdd_name`
        2. `tipoemision`
        3. `emision`
        4. `vigencia`
        5. `pedidos`
        6. `ventas`
        7. `compras`
        8. `evale`
        9. `ereceiv`
        10. `email`
        11. `lghost_fe_fv`
        12. `lghost_fe_nc`
        13. `lghost_fe_nd`
        14. `lghost_fe_gr`
        15. `lghost_fe_cr`
        16. `correo`
        17. `etiq_correo`
        18. `emision`

        If the emitter is not found, the endpoint returns `*`.
      parameters:
        - in: query
          name: id
          required: true
          schema:
            type: string
          example: '1104732043001'
      responses:
        '200':
          description: Pipe-delimited emitter data
          content:
            text/plain:
              schema:
                type: string
              examples:
                found:
                  summary: Existing emitter
                  value: "ghost_legacy|1|PRODUCCION|2026-12-31|1|1|0|0|1|1|1|1|1|1|0|soporte@empresa.com|FACTURA ELECTRONICA|PRODUCCION"
                missing:
                  summary: Missing emitter
                  value: "*"
  /fe2/get_data.php:
    get:
      summary: Get full emitter row as JSON
      description: |
        Looks up one emitter in the `bdd` table by RUC and returns the full database row as JSON.

        This is a metadata/config endpoint, not a document endpoint. Compared with `getghost.php`, this route returns the whole emitter record instead of a selected pipe-delimited subset.

        If the emitter is not found, the endpoint returns the legacy sentinel string `@@` instead of JSON.
      parameters:
        - in: query
          name: ruce
          required: true
          schema:
            type: string
          example: '1104732043001'
      responses:
        '200':
          description: JSON representation of the emitter row, or `@@` when missing
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
              examples:
                found:
                  summary: Existing emitter
                  value:
                    id: "3"
                    ruc: "1104732043001"
                    bdd_name: "ghost_legacy"
                    frm01: "rpt_factura"
                    tipoemision: "1"
                    emision: "PRODUCCION"
                missing:
                  summary: Missing emitter
                  value: "@@"
  /fe2/get_email_config.php:
    get:
      summary: Get emitter email configuration text
      description: |
        Returns the legacy email configuration/template text associated with an emitter.

        This endpoint does not read the config directly from the database row. Instead:
        1. It looks up the emitter in `bdd` by `ruce`
        2. It takes the emitter `id`
        3. It reads `fe2/emails/{id}.txt`

        If no emitter-specific file exists, it falls back to the default file `fe2/emails/0.txt`.

        The response is plain text after `utf8_encode()`.
      parameters:
        - in: query
          name: ruce
          required: true
          schema:
            type: string
          example: '1104732043001'
      responses:
        '200':
          description: Plain text email configuration, or the default fallback text when no emitter-specific file exists
          content:
            text/plain:
              schema:
                type: string
              examples:
                emitterSpecific:
                  summary: Emitter-specific email config
                  value: |
                    EMAIL_FROM=soporte@empresa.com
                    EMAIL_NAME=Facturacion Electronica
                    SUBJECT=Comprobante electronico
                fallback:
                  summary: Default fallback config
                  value: |
                    EMAIL_FROM=no-reply@example.com
                    EMAIL_NAME=Ghost Legacy
  /visualplus/index.php:
    get:
      summary: VisualPlus login page
      parameters:
        - in: query
          name: ruce
          required: false
          schema:
            type: string
        - in: query
          name: entrada
          required: false
          schema:
            type: string
      responses:
        '200':
          description: HTML login UI
          content:
            text/html:
              schema:
                type: string
    post:
      summary: VisualPlus login submit
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required:
                - usuario
                - password
              properties:
                usuario:
                  type: string
                password:
                  type: string
      responses:
        '200':
          description: Login page or redirect
  /visualplus/mapa.php:
    get:
      summary: VisualPlus main UI
      parameters:
        - in: query
          name: startDate
          required: false
          schema:
            type: string
            format: date
        - in: query
          name: endDate
          required: false
          schema:
            type: string
            format: date
        - in: query
          name: ruce
          required: false
          schema:
            type: string
      responses:
        '200':
          description: HTML document listing UI
          content:
            text/html:
              schema:
                type: string
  /visualplus/ajax.php:
    get:
      summary: VisualPlus JSON endpoint
      parameters:
        - in: query
          name: ruc
          required: true
          schema:
            type: string
        - in: query
          name: type
          required: true
          schema:
            type: string
            enum: [entidad, facturas, updateEmisores]
        - in: query
          name: fdesde
          required: false
          schema:
            type: string
            format: date
        - in: query
          name: fhasta
          required: false
          schema:
            type: string
            format: date
        - in: query
          name: TipoDoc
          required: false
          schema:
            type: integer
      responses:
        '200':
          description: JSON payload used by the VisualPlus UI
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: boolean
                  data:
                    type: array
                    items:
                      oneOf:
                        - type: object
                          additionalProperties: true
                        - type: array
                          items: {}
