openapi: 3.1.0
info:
  title: Firux Partner API
  version: "2026-07-25"
  description: >
    API para integradores (partners) y comercios que crean cobros Bre-B por API y
    reciben la confirmación por webhook firmado. El dinero llega siempre a la cuenta
    Bre-B del comercio; la API nunca mueve ni retiene fondos. Los montos van y vuelven
    en pesos colombianos (COP) enteros, sin decimales.
  contact:
    name: Soporte Firux Pay
    email: soporte@firux.co

servers:
  - url: https://api.firux.co/v1
    description: Subdominio dedicado de la API (única URL pública)

security:
  - bearerAuth: []

tags:
  - name: Cobros
    description: Crear y consultar cobros

paths:
  /charges:
    post:
      tags: [Cobros]
      summary: Crear un cobro
      description: >
        Crea un cobro Bre-B. Requiere el header Idempotency-Key. Si se reenvía la
        misma external_reference y el cobro sigue pendiente con el mismo monto, se
        devuelve el cobro existente (200) en vez de crear otro.
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateChargeRequest'
      responses:
        '201':
          description: Cobro creado
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Charge' }
        '200':
          description: Ya existía un cobro pendiente con esa external_reference y monto
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Charge' }
        '400': { $ref: '#/components/responses/Error' }
        '401': { $ref: '#/components/responses/Error' }
        '409':
          description: external_reference ya pagada o en conflicto / solicitud en proceso
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorWithCharge' }
        '422': { $ref: '#/components/responses/Error' }
        '503': { $ref: '#/components/responses/Error' }
    get:
      tags: [Cobros]
      summary: Buscar cobros por external_reference
      parameters:
        - name: external_reference
          in: query
          required: true
          schema: { type: string }
      responses:
        '200':
          description: Lista de cobros
          content:
            application/json:
              schema:
                type: object
                properties:
                  object: { type: string, const: list }
                  data:
                    type: array
                    items: { $ref: '#/components/schemas/Charge' }

  /charges/{id}:
    get:
      tags: [Cobros]
      summary: Consultar un cobro
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
          description: Id del cobro (con o sin prefijo chg_).
      responses:
        '200':
          description: Cobro
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Charge' }
        '404': { $ref: '#/components/responses/Error' }

  /charges/{id}/simulate_payment:
    post:
      tags: [Cobros]
      summary: Simular el pago (solo entorno test)
      description: >
        Dispara el evento charge.paid del cobro sin mover dinero real. Solo funciona
        con credenciales de prueba (firux_test_...). Ideal para probar tu webhook.
      parameters:
        - name: id
          in: path
          required: true
          schema: { type: string }
      responses:
        '200':
          description: Evento simulado y encolado
          content:
            application/json:
              schema:
                type: object
                properties:
                  object: { type: string, const: simulation }
                  message: { type: string }
                  event_id: { type: string }
        '403': { $ref: '#/components/responses/Error' }
        '404': { $ref: '#/components/responses/Error' }

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >
        API key del comercio, en el header Authorization: Bearer firux_live_... (o
        firux_test_... en pruebas). Se genera y se muestra una sola vez desde el panel
        del comercio (Ajustes -> Conexiones API).

  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      schema: { type: string, maxLength: 120 }
      description: >
        Clave única de tu lado por intento de creación. Reenviar la misma clave con el
        mismo cuerpo devuelve el mismo cobro (no crea duplicados).

  schemas:
    CreateChargeRequest:
      type: object
      required: [amount, external_reference]
      properties:
        amount:
          type: integer
          minimum: 1
          description: Monto en pesos COP enteros (sin decimales).
          example: 50000
        external_reference:
          type: string
          maxLength: 255
          description: Tu referencia (id de factura/pedido). Es la llave con la que concilias.
          example: FACT-2026-00123
        description:
          type: string
          maxLength: 255
          example: Mensualidad julio - Club Deportivo
        expires_at:
          type: string
          format: date-time
          description: Vencimiento opcional del cobro.
        metadata:
          type: object
          maxProperties: 20
          additionalProperties: { type: [string, number, boolean, "null"] }
          description: Datos propios (máx. 4 KB). Se devuelven tal cual; Firux no los interpreta.

    Charge:
      type: object
      properties:
        id: { type: string, example: chg_9f8c... }
        object: { type: string, const: charge }
        status:
          type: string
          enum: [PENDING, PAID, EXPIRED, FAILED]
        amount: { type: integer, description: Pesos COP, example: 50000 }
        amount_paid: { type: [integer, "null"], description: Pesos COP realmente pagados }
        currency: { type: string, const: COP }
        external_reference: { type: [string, "null"] }
        reference: { type: string, description: Referencia interna de Firux }
        description: { type: [string, "null"] }
        metadata: { type: [object, "null"] }
        payment_url: { type: string, description: Página de pago para el pagador }
        qr_emv: { type: [string, "null"], description: Cadena EMV del QR Bre-B }
        payment_method: { type: string, const: BRE_B }
        paid_at: { type: [string, "null"], format: date-time }
        created_at: { type: string, format: date-time }

    WebhookEvent:
      type: object
      description: Cuerpo del webhook (POST a tu URL). Verifica la firma antes de confiar en él.
      properties:
        id: { type: string, example: evt_... }
        type: { type: string, example: charge.paid }
        api_version: { type: string, example: "2026-07-25" }
        created_at: { type: string, format: date-time }
        livemode: { type: boolean }
        simulated: { type: boolean, description: true si vino de simulate_payment o prueba }
        data:
          type: object
          properties:
            charge_id: { type: string }
            merchant_id: { type: string }
            integration_id: { type: [string, "null"] }
            status: { type: string, const: PAID }
            amount: { type: integer }
            amount_paid: { type: integer }
            currency: { type: string, const: COP }
            external_reference: { type: [string, "null"] }
            reference: { type: string }
            description: { type: [string, "null"] }
            metadata: { type: [object, "null"] }
            paid_at: { type: [string, "null"], format: date-time, description: Movimiento en el banco }
            detected_at: { type: [string, "null"], format: date-time, description: Cuándo lo vio Firux }
            payment_method: { type: string, const: BRE_B }

    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            type: { type: string, example: validation_error }
            message: { type: string }
            fields:
              type: object
              additionalProperties: true

    ErrorWithCharge:
      allOf:
        - $ref: '#/components/schemas/Error'
        - type: object
          properties:
            error:
              type: object
              properties:
                charge: { $ref: '#/components/schemas/Charge' }

  responses:
    Error:
      description: Error
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
