openapi: 3.0.3
info:
  title: SpinBank API
  version: 1.0.0
  description: API wrapper leve para expor endpoints de pagamentos via CodeIgniter 4.
servers:
  - url: http://localhost:8088
security:
  - ApiKeyAuth: []
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-KEY
tags:
  - name: Cobranças
    description: Operações de criação e consulta de cobranças (Pix In)
  - name: Pagamentos
    description: Operações de criação, aprovação e consulta de pagamentos (Pix Out)
  - name: Transações
    description: Consulta de transações do cliente autenticado
  - name: Callback
    description: Endpoint público para receber webhooks do provedor
  - name: Admin - Clientes
    description: Gestão de clientes (criação, webhook, rotação de chave)
  - name: Admin - Taxas
    description: Configuração e listagem de taxas por cliente
  - name: Admin - Webhooks
    description: Operações administrativas relacionadas a webhooks
x-tagGroups:
  - name: Cliente
    tags:
      - Cobranças
      - Pagamentos
      - Transações
      - Callback
  - name: Admin
    tags:
      - Admin - Clientes
      - Admin - Taxas
      - Admin - Webhooks
paths:
  /v1/charge:
    post:
      tags: [Cobranças]
      summary: Criar cobrança (Pix In)
      description: Cria uma cobrança (transação de entrada). Requer autenticação por chave do wrapper.
      security:
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                value:
                  type: integer
                  example: 1000
                correlationID:
                  type: string
                  example: order-123
                customer:
                  type: object
                  properties:
                    name:
                      type: string
                      example: Cliente Teste
                    taxID:
                      type: string
                      example: '00000000000'
            examples:
              exemplo:
                summary: Exemplo de criação de cobrança
                value:
                  value: 1000
                  correlationID: order-123
                  customer:
                    name: Cliente Teste
                    taxID: '00000000000'
      x-codeSamples:
        - lang: curl
          label: curl
          source: |
            curl -X POST "{{baseUrl}}/v1/charge" \
              -H "Content-Type: application/json" \
              -H "X-API-KEY: {{apiKey}}" \
              -d '{
                "value": 1000,
                "correlationID": "order-123",
                "customer": {"name": "Cliente Teste", "taxID": "00000000000"}
              }'
      responses:
        '201':
          description: Criado
          content:
            application/json:
              schema:
                type: object
                properties:
                  customer:
                    type: object
                    properties:
                      name:
                        type: string
                  correlationID:
                    type: string
                  charge:
                    type: object
                    properties:
                      value: { type: integer }
                      identifier: { type: string }
                      transactionID: { type: string }
                      status: { type: string }
                      qrCodeImage: { type: string }
                      brCode: { type: string }
                      expiresIn: { type: integer }
              examples:
                exemplo:
                  value:
                    customer:
                      name: Cliente Teste
                    correlationID: order-123
                    charge:
                      value: 1000
                      identifier: 21d0...
                      transactionID: 21d0...
                      status: ACTIVE
                      qrCodeImage: https://...
                      brCode: 00020126...
                      expiresIn: 86400
  /v1/charge/{id}:
    get:
      tags: [Cobranças]
      summary: Consultar cobrança
      description: Consulta o status de uma cobrança pelo ID.
      security:
        - ApiKeyAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  customer:
                    type: object
                    properties:
                      name:
                        type: string
                  correlationID:
                    type: string
                  charge:
                    type: object
                    properties:
                      value: { type: integer }
                      identifier: { type: string }
                      transactionID: { type: string }
                      status: { type: string }
                      qrCodeImage: { type: string }
                      brCode: { type: string }
                      expiresIn: { type: integer }
      x-codeSamples:
        - lang: curl
          label: curl
          source: |
            curl -X GET "{{baseUrl}}/v1/charge/{id}" -H "X-API-KEY: {{apiKey}}"
  /v1/payment:
    post:
      tags: [Pagamentos]
      summary: Criar pagamento (PIX_KEY)
      description: Cria um pagamento Pix via chave (proxy para /payment).
        - Se `SUBACCOUNT_ID` estiver definido, o wrapper valida o saldo da subconta (`GET /subaccount/{id}`) e debita (`POST /subaccount/{id}/debit`) antes de criar o pagamento. Caso o valor seja maior que o saldo, retorna 400 ("Saldo insuficiente").
        - Se `PAYMENT_AUTO_APPROVE=true`, o wrapper aprova automaticamente via `/payment/approve` usando o `correlationID` informado e retorna ambos os resultados.
      security:
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                type:
                  type: string
                  example: PIX_KEY
                value:
                  type: integer
                  example: 1000
                destinationAlias:
                  type: string
                  example: '+5511888888888'
                destinationAliasType:
                  type: string
                  enum: [CPF, CNPJ, EMAIL, PHONE, RANDOM]
                  example: PHONE
                correlationID:
                  type: string
                  example: payout-123
                pixKeyEndToEndId:
                  type: string
                comment:
                  type: string
                metadata:
                  type: object
            examples:
              exemplo:
                value:
                  type: PIX_KEY
                  value: 1000
                  destinationAlias: '+5511888888888'
                  destinationAliasType: PHONE
                  correlationID: payout-123
                  comment: opcional
      x-codeSamples:
        - lang: curl
          label: curl
          source: |
            curl -X POST "{{baseUrl}}/v1/payment" \
              -H "Content-Type: application/json" \
              -H "X-API-KEY: {{apiKey}}" \
              -d '{"type":"PIX_KEY","value":1000,"destinationAlias":"+5511888888888","destinationAliasType":"PHONE","correlationID":"payout-123"}'
      responses:
        '201':
          description: Criado
          content:
            application/json:
              examples:
                exemplo:
                  value:
                    id: pay_123
                    value: 1000
                    correlationID: payout-123
                    status: PROCESSING
  /v1/payment/{id}:
    get:
      tags: [Pagamentos]
      summary: Consultar pagamento
      description: Consulta o status de um pagamento pelo ID.
      security:
        - ApiKeyAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              examples:
                exemplo:
                  value:
                    id: pay_123
                    status: COMPLETED
                    value: 1000
      x-codeSamples:
        - lang: curl
          label: curl
          source: |
            curl -X GET "{{baseUrl}}/v1/payment/{id}" -H "X-API-KEY: {{apiKey}}"
  /v1/payment/approve:
    post:
      tags: [Pagamentos]
      summary: Aprovar pagamento
      description: Aprova um pagamento pelo correlationID (proxy para /payment/approve).
      security:
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [correlationID]
              properties:
                correlationID:
                  type: string
            examples:
              exemplo:
                value:
                  correlationID: payout-123
      x-codeSamples:
        - lang: curl
          label: curl
          source: |
            curl -X POST "{{baseUrl}}/v1/payment/approve" \
              -H "Content-Type: application/json" \
              -H "X-API-KEY: {{apiKey}}" \
              -d '{"correlationID":"payout-123"}'
      responses:
        '200':
          description: OK

  /v1/transactions:
    get:
      tags: [Transações]
      summary: Listar transações do cliente autenticado
      security:
        - ApiKeyAuth: []
      parameters:
        - in: query
          name: type
          schema: { type: string, enum: [IN, OUT] }
        - in: query
          name: status
          schema: { type: string }
        - in: query
          name: limit
          schema: { type: integer, default: 50 }
        - in: query
          name: offset
          schema: { type: integer, default: 0 }
      responses:
        '200': { description: OK }

  # Admin endpoints (usam ApiKeyAuth com ADMIN_API_KEY)
  /v1/admin/clients:
    post:
      tags: [Admin - Clientes]
      summary: Criar cliente (gera apiKey e cria subconta)
      description: Requer ADMIN_API_KEY via header X-API-KEY.
      security:
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [name, pixKey]
              properties:
                name: { type: string }
                pixKey: { type: string }
      responses:
        '201':
          description: Criado (retorna apiKey apenas uma vez)
  /v1/admin/clients/{id}/webhook:
    put:
      tags: [Admin - Clientes]
      summary: Definir webhook do cliente
      security:
        - ApiKeyAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema: { type: integer }
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [webhook_url]
              properties:
                webhook_url: { type: string }
      responses:
        '200': { description: OK }
  /v1/admin/fees:
    post:
      tags: [Admin - Taxas]
      summary: Criar taxa
      security:
        - ApiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [client_id, kind]
              properties:
                client_id: { type: integer }
                kind: { type: string, enum: [PIX_IN, PIX_OUT] }
                percent_bps: { type: integer }
                fixed_cents: { type: integer }
                active_from: { type: string }
                active_to: { type: string }
      responses:
        '201': { description: Criado }
    get:
      tags: [Admin - Taxas]
      summary: Listar taxas
      security:
        - ApiKeyAuth: []
      parameters:
        - in: query
          name: client_id
          required: false
          schema: { type: integer }
        - in: query
          name: kind
          required: false
          schema: { type: string, enum: [PIX_IN, PIX_OUT] }
      responses:
        '200': { description: OK }
  /v1/admin/webhooks/resend:
    post:
      tags: [Admin - Webhooks]
      summary: Reenviar webhooks pendentes
      security:
        - ApiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                event_id: { type: integer }
                client_id: { type: integer }
                only_unprocessed: { type: boolean }
      responses:
        '200': { description: OK }
  /v1/callback/woovi:
    post:
      tags: [Callback]
      summary: Callback público de webhooks do provedor
      responses:
        '204':
          description: Sem conteúdo

