openapi: 3.1.0

info:
  title: Lion Tech Pay API
  version: 1.0.0
  description: |
    # Bem-vindo à API Lion Tech Pay

    A **Lion Tech Pay** é uma plataforma de pagamentos focada no mercado brasileiro.
    Com nossa API você pode receber pagamentos via **PIX**, realizar **transferências PIX**,
    consultar seu **saldo**, configurar **split de pagamentos** e **webhooks** para notificações em tempo real.

    ## Como começar

    1. Acesse o [Dashboard](https://www.liontechpay.com) e gere suas credenciais em **Configurações → API Keys**
    2. Autentique-se enviando `client_id:client_secret` para `POST /api/auth`
    3. Use o **Bearer token** retornado em todas as requisições

    ## Base URL

    ```
    https://api.liontechpay.com
    ```

    ## Valores monetários

    Todos os valores são em **centavos (inteiros)**.

    | Valor real | Em centavos |
    |------------|-------------|
    | R$ 1,00    | `100`       |
    | R$ 10,50   | `1050`      |
    | R$ 150,00  | `15000`     |

    ## Idempotência

    Para transferências PIX, envie o header `x-idempotency-key` com um valor único por operação.
    Isso garante que em caso de retry a operação não seja duplicada.

  contact:
    name: Suporte Lion Tech Pay
    email: suporte@liontechpay.com
    url: https://liontechpay.com

servers:
  - url: https://api.liontechpay.com
    description: API Lion Tech Pay

tags:
  - name: Autenticação
    description: |
      Geração de tokens de acesso via API Key.

      Use suas credenciais (`client_id` e `client_secret`) com **Basic Auth** para obter um JWT Bearer token.
      O token é necessário em todas as demais rotas.

  - name: PIX IN
    description: |
      Receba pagamentos instantâneos via QR Code PIX.

      Crie um QR Code e exiba para o seu cliente pagar. Ao receber o pagamento, você será
      notificado via webhook (se configurado).

  - name: PIX OUT
    description: |
      Envie transferências PIX para qualquer chave PIX.

      Suporta chaves do tipo CPF, CNPJ, e-mail, telefone e chave aleatória (EVP).
      Requer o header `x-idempotency-key` para evitar duplicações.

  - name: Sandbox
    description: |
      Ambiente de testes isolado, com seu próprio par de credenciais (gerado no
      Dashboard em **Chaves de API → Sandbox**).

      Toda cobrança criada com uma chave sandbox transaciona contra um adquirente
      simulado e **nunca movimenta dinheiro real**. Pagamentos PIX não são confirmados
      automaticamente — use os endpoints de simulação abaixo para disparar manualmente
      o webhook `transaction_paid` / `transfer_completed`, exatamente como aconteceria
      em produção.

      Os demais endpoints da API (criar cobrança, consultar, criar transferência,
      configurar webhooks) funcionam de forma idêntica em ambos os ambientes — a única
      diferença é qual par de credenciais você usa em `POST /api/auth`.

  - name: Saldo
    description: |
      Consulte os saldos das carteiras da sua conta em tempo real.

      Os valores são retornados em **reais** (string com 2 casas decimais).

      | Campo | Descrição |
      |-------|-----------|
      | `pix.balance` | Saldo disponível para uso |
      | `pixBlocked.balance` | Saldo bloqueado (cautelar / MED) |
      | `reserve.balance` | Valor em reserva |

  - name: Webhooks
    description: |
      Receba notificações em tempo real sobre eventos da sua conta.

      Configure uma URL e escolha quais eventos deseja monitorar.
      A Lion Tech Pay enviará um `POST` com o payload do evento para a URL configurada.

      Além dos webhooks cadastrados em `/api/v1/webhook`, quando uma cobrança ou
      transferência é criada com `postbackUrl`, o mesmo callback também é enviado para
      essa URL.

      ### Eventos disponíveis

      Use os eventos abaixo no campo `events` ao criar um webhook.

      | Fluxo | Evento | Quando é enviado |
      |-------|--------|------------------|
      | PIX IN | `transaction_created` | Cobrança PIX criada |
      | PIX IN | `transaction_paid` | Cobrança PIX paga |
      | PIX IN | `transaction_refunded` | Cobrança PIX estornada |
      | PIX IN | `transaction_updated` | Cobrança PIX atualizada com outro status |
      | PIX IN | `infraction` | Infração/MED criada ou atualizada para uma cobrança PIX |
      | PIX OUT | `transfer_created` | Transferência PIX criada |
      | PIX OUT | `transfer_updated` | Transferência PIX atualizada com outro status |
      | PIX OUT | `transfer_completed` | Transferência PIX concluída |
      | PIX OUT | `transfer_canceled` | Transferência PIX cancelada ou recusada |

      ### Headers enviados no callback

      | Header | Valor |
      |--------|-------|
      | `Content-Type` | `application/json` |
      | `User-Agent` | `LionTechPay` |
      | `Lion-Signature` | Assinatura HMAC-SHA256 no formato `t={timestamp},v1={hash}` quando o webhook possui `signatureSecret` |

      ### Payload de PIX IN

      Enviado nos eventos `transaction_created`, `transaction_paid`, `transaction_refunded`
      e `transaction_updated`.

      ```json
      {
        "id": "8d0f3b8f-5c2f-4a10-8dd6-8bbf5e9b1d11",
        "type": "transaction",
        "event": "transaction_paid",
        "scope": "user",
        "transaction": {
          "id": "transaction_abc123",
          "amount": 5000,
          "status": "paid",
          "pix": {
            "endToEndId": "E1234567820241231000000000000001",
            "payerInfo": {
              "name": "Joao Silva",
              "document": "11122233344"
            }
          }
        }
      }
      ```

      ### Payload de PIX OUT

      Enviado nos eventos `transfer_created`, `transfer_updated`, `transfer_completed`
      e `transfer_canceled`.

      ```json
      {
        "id": "5f9e0c94-60a4-4df8-bb81-7f6efc6f61b0",
        "type": "transfer",
        "event": "transfer_completed",
        "scope": "user",
        "transfer": {
          "id": "transfer_abc123",
          "amount": 10000,
          "status": "paid",
          "pix": {
            "endToEndId": "E1234567820241231000000000000002",
            "creditorAccount": {
              "name": "Fornecedor Exemplo",
              "document": "12345678000199"
            }
          }
        }
      }
      ```

      ### Payload de infração PIX IN

      Enviado no evento `infraction`.

      ```json
      {
        "id": "3db3ac40-a069-45e6-8cb8-6d55d09f516d",
        "type": "infraction",
        "event": "infraction",
        "scope": "user",
        "infraction": {
          "id": "infraction_abc123",
          "amount": 5000,
          "status": "OPEN",
          "pix": {
            "endToEndId": "E1234567820241231000000000000001"
          }
        },
        "transaction": {
          "id": "transaction_abc123",
          "amount": 5000,
          "status": "infraction",
          "pix": {
            "endToEndId": "E1234567820241231000000000000001",
            "payerInfo": {
              "name": "Joao Silva",
              "document": "11122233344"
            }
          }
        }
      }
      ```

  - name: Formato dos Webhooks
    description: |
      Exemplos dos payloads enviados pela Lion Tech Pay nos callbacks.

      Esta seção é apenas referência de formato. Os callbacks são enviados via `POST`
      para a URL configurada no webhook ou no `postbackUrl`.

paths:

  # ─────────────────────────────────────────────
  # AUTENTICAÇÃO
  # ─────────────────────────────────────────────
  /api/auth:
    post:
      tags:
        - Autenticação
      summary: Gerar token de acesso
      operationId: auth-generate-token
      description: |
        Gera um **token JWT** para autenticar as demais requisições da API.

        ### Como montar o header Basic Auth

        Concatene `client_id:client_secret` e codifique em **Base64**:

        ```bash
        echo -n "SUA_API_KEY:SEU_API_SECRET" | base64
        # → U1VBX0FQSV9LRVk6U0VVX0FQSV9TRUNSRVQ=
        ```

        Então envie no header:
        ```
        Authorization: Basic U1VBX0FQSV9LRVk6U0VVX0FQSV9TRUNSRVQ=
        ```

        > ⚠️ Esta rota **não aceita body**. Apenas o header `Authorization`.

        ### Token retornado

        Use o `token` retornado como Bearer em todas as outras rotas:
        ```
        Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
        ```
      security:
        - basicAuth: []
      x-codeSamples:
        - lang: Shell
          label: cURL
          source: |
            curl -X POST 'https://api.liontechpay.com/api/auth' \
              -H 'Authorization: Basic SEU_BASIC_AUTH_AQUI'
        - lang: JavaScript
          label: Node.js
          source: |
            const credentials = Buffer.from('SUA_API_KEY:SEU_API_SECRET').toString('base64')

            const response = await fetch('https://api.liontechpay.com/api/auth', {
              method: 'POST',
              headers: {
                'Authorization': `Basic ${credentials}`
              }
            })

            const { token } = await response.json()
        - lang: Python
          label: Python
          source: |
            import requests
            import base64

            credentials = base64.b64encode(b'SUA_API_KEY:SEU_API_SECRET').decode()

            response = requests.post(
                'https://api.liontechpay.com/api/auth',
                headers={'Authorization': f'Basic {credentials}'}
            )

            token = response.json()['token']
        - lang: PHP
          label: PHP
          source: |
            $credentials = base64_encode('SUA_API_KEY:SEU_API_SECRET');

            $ch = curl_init('https://api.liontechpay.com/api/auth');
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
                'Authorization: Basic ' . $credentials
            ]);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

            $response = json_decode(curl_exec($ch), true);
            $token = $response['token'];
      responses:
        '200':
          description: Token gerado com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  token:
                    type: string
                    description: JWT Bearer token — use em todas as próximas requisições
                    example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOnsiY29tcGFueSI6eyJpZCI6ImNseDFhYmMifX19..."
                  tokenType:
                    type: string
                    example: "Bearer"
                  expiresIn:
                    type: integer
                    description: Tempo de expiração em milissegundos
                    example: 60000
              example:
                success: true
                token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
                tokenType: "Bearer"
                expiresIn: 60000
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'

  # ─────────────────────────────────────────────
  # PIX IN
  # ─────────────────────────────────────────────
  /api/v1/pix/in/qrcode:
    post:
      tags:
        - PIX IN
      summary: Criar QR Code PIX
      operationId: pix-in-create-qrcode
      description: |
        Cria um **QR Code PIX** para receber um pagamento imediato.

        Retorna o **código EMV** (copia e cola) e a **imagem Base64** do QR Code,
        prontos para exibir ao seu cliente.

        ### Fluxo completo

        ```
        1. Sua aplicação chama POST /api/v1/pix/in/qrcode
        2. Lion Tech Pay retorna emv + qrCode (Base64)
        3. Você exibe o QR Code ao cliente
        4. Cliente paga no app do banco
        5. Lion Tech Pay envia notificação no postbackUrl (se informado)
        ```

        ### Recebendo a confirmação

        Configure `postbackUrl` para receber uma notificação automática quando o pagamento
        for confirmado, sem precisar fazer polling.
      security:
        - bearerAuth: []
      x-codeSamples:
        - lang: Shell
          label: cURL
          source: |
            curl -X POST 'https://api.liontechpay.com/api/v1/pix/in/qrcode' \
              -H 'Authorization: Bearer SEU_TOKEN_AQUI' \
              -H 'Content-Type: application/json' \
              -d '{
                "amountInCents": 5000,
                "description": "Pagamento de serviços",
                "postbackUrl": "https://exemplo.com.br/webhook",
                "customer": {
                  "name": "João Silva",
                  "email": "joao@exemplo.com",
                  "documentType": "cpf",
                  "document": "11122233344",
                  "phone": "(11) 91234-5678"
                }
              }'
        - lang: JavaScript
          label: Node.js
          source: |
            const response = await fetch('https://api.liontechpay.com/api/v1/pix/in/qrcode', {
              method: 'POST',
              headers: {
                'Authorization': 'Bearer SEU_TOKEN_AQUI',
                'Content-Type': 'application/json'
              },
              body: JSON.stringify({
                amountInCents: 5000,
                description: 'Pagamento de serviços',
                postbackUrl: 'https://exemplo.com.br/webhook',
                customer: {
                  name: 'João Silva',
                  email: 'joao@exemplo.com',
                  documentType: 'cpf',
                  document: '11122233344',
                  phone: '(11) 91234-5678'
                }
              })
            })

            const { data } = await response.json()
            console.log(data.pix.emv)    // código copia e cola
            console.log(data.pix.qrCode) // imagem Base64
        - lang: Python
          label: Python
          source: |
            import requests

            response = requests.post(
                'https://api.liontechpay.com/api/v1/pix/in/qrcode',
                headers={
                    'Authorization': 'Bearer SEU_TOKEN_AQUI',
                    'Content-Type': 'application/json'
                },
                json={
                    'amountInCents': 5000,
                    'description': 'Pagamento de servicos',
                    'postbackUrl': 'https://exemplo.com.br/webhook',
                    'customer': {
                        'name': 'Joao Silva',
                        'email': 'joao@exemplo.com',
                        'documentType': 'cpf',
                        'document': '11122233344',
                        'phone': '(11) 91234-5678'
                    }
                }
            )

            data = response.json()['data']
            print(data['pix']['emv'])
        - lang: PHP
          label: PHP
          source: |
            $payload = json_encode([
                'amountInCents' => 5000,
                'description' => 'Pagamento de servicos',
                'postbackUrl' => 'https://exemplo.com.br/webhook',
                'customer' => [
                    'name' => 'Joao Silva',
                    'email' => 'joao@exemplo.com',
                    'documentType' => 'cpf',
                    'document' => '11122233344',
                    'phone' => '(11) 91234-5678'
                ]
            ]);

            $ch = curl_init('https://api.liontechpay.com/api/v1/pix/in/qrcode');
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
                'Authorization: Bearer SEU_TOKEN_AQUI',
                'Content-Type: application/json'
            ]);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

            $response = json_decode(curl_exec($ch), true);
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - amountInCents
                - customer
              properties:
                amountInCents:
                  type: integer
                  minimum: 100
                  description: Valor da cobrança em centavos (mínimo R$ 1,00)
                  example: 5000
                description:
                  type: string
                  maxLength: 140
                  description: Descrição que aparecerá no extrato do pagador
                  example: "Pagamento de serviços"
                postbackUrl:
                  type: string
                  format: uri
                  description: URL para receber notificação quando o pagamento for confirmado
                  example: "https://exemplo.com.br/webhook"
                customer:
                  $ref: '#/components/schemas/Customer'
                items:
                  type: array
                  description: Itens do pedido (opcional)
                  items:
                    type: object
                    required:
                      - title
                      - tangible
                      - quantity
                      - amountInCents
                    properties:
                      title:
                        type: string
                        example: "Produto A"
                      tangible:
                        type: boolean
                        example: true
                      quantity:
                        type: integer
                        example: 2
                      amountInCents:
                        type: integer
                        example: 2500
                      shippingAddress:
                        $ref: '#/components/schemas/Address'
                splits:
                  type: array
                  description: |
                    Distribui automaticamente parte do valor líquido para outras empresas Lion Tech Pay.
                    A soma dos percentuais não pode ultrapassar 100%.
                    O split é executado no momento em que o pagamento é confirmado.
                  items:
                    $ref: '#/components/schemas/SplitItem'
            examples:
              minimo:
                summary: Cobrança mínima
                value:
                  amountInCents: 5000
                  customer:
                    name: "João Silva"
                    email: "joao@exemplo.com"
                    documentType: "cpf"
                    document: "11122233344"
                    phone: "(11) 91234-5678"
              completo:
                summary: Cobrança com itens e webhook
                value:
                  amountInCents: 15000
                  description: "Pedido #1234"
                  postbackUrl: "https://exemplo.com.br/webhook"
                  customer:
                    name: "Maria Souza"
                    email: "maria@exemplo.com"
                    documentType: "cpf"
                    document: "99988877766"
                    phone: "(21) 98765-4321"
                  items:
                    - title: "Produto A"
                      tangible: true
                      quantity: 2
                      amountInCents: 5000
                    - title: "Produto B"
                      tangible: true
                      quantity: 1
                      amountInCents: 5000
              comSplit:
                summary: Cobrança com split entre parceiros
                value:
                  amountInCents: 20000
                  description: "Venda marketplace #5678"
                  postbackUrl: "https://exemplo.com.br/webhook"
                  customer:
                    name: "Carlos Ferreira"
                    email: "carlos@exemplo.com"
                    documentType: "cpf"
                    document: "33344455566"
                    phone: "(31) 97777-8888"
                  splits:
                    - email: "parceiro1@empresa.com"
                      percentage: 30
                    - email: "parceiro2@empresa.com"
                      percentage: 15
      responses:
        '200':
          description: QR Code PIX criado com sucesso
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PixQRCodeResponse'
              example:
                success: true
                message: "Transação criada com sucesso"
                data:
                  id: "trx_1a2b3c4d5e6f7g8h9i0j"
                  pix:
                    emv: "00020126580014br.gov.bcb.pix0136..."
                    qrCode: "iVBORw0KGgo..."
                  status: "pending"
                  fees: 0
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/pix/in/qrcode/{transactionId}:
    get:
      tags:
        - PIX IN
      summary: Consultar QR Code PIX
      operationId: pix-in-get-qrcode
      description: |
        Consulta uma cobrança PIX criada anteriormente e retorna o **EMV** e a
        **imagem Base64** do QR Code.

        Use o `id` retornado na criação do QR Code.
      security:
        - bearerAuth: []
      parameters:
        - name: transactionId
          in: path
          required: true
          description: ID da transação retornado na criação do QR Code
          schema:
            type: string
            example: "trx_1a2b3c4d5e6f7g8h9i0j"
      x-codeSamples:
        - lang: Shell
          label: cURL
          source: |
            curl -X GET 'https://api.liontechpay.com/api/v1/pix/in/qrcode/trx_1a2b3c4d5e6f7g8h9i0j' \
              -H 'Authorization: Bearer SEU_TOKEN_AQUI'
        - lang: JavaScript
          label: Node.js
          source: |
            const transactionId = 'trx_1a2b3c4d5e6f7g8h9i0j'

            const response = await fetch(
              `https://api.liontechpay.com/api/v1/pix/in/qrcode/${transactionId}`,
              {
                headers: { 'Authorization': 'Bearer SEU_TOKEN_AQUI' }
              }
            )

            const { data } = await response.json()
            console.log(data.pix.emv)
            console.log(data.pix.qrCode)
        - lang: Python
          label: Python
          source: |
            import requests

            transaction_id = 'trx_1a2b3c4d5e6f7g8h9i0j'
            response = requests.get(
                f'https://api.liontechpay.com/api/v1/pix/in/qrcode/{transaction_id}',
                headers={'Authorization': 'Bearer SEU_TOKEN_AQUI'}
            )

            data = response.json()['data']
            print(data['pix']['emv'])
        - lang: PHP
          label: PHP
          source: |
            $transactionId = 'trx_1a2b3c4d5e6f7g8h9i0j';

            $ch = curl_init("https://api.liontechpay.com/api/v1/pix/in/qrcode/{$transactionId}");
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
                'Authorization: Bearer SEU_TOKEN_AQUI'
            ]);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

            $response = json_decode(curl_exec($ch), true);
      responses:
        '200':
          description: QR Code PIX encontrado com sucesso
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PixQRCodeResponse'
              example:
                success: true
                message: "QR Code PIX encontrado com sucesso"
                data:
                  id: "trx_1a2b3c4d5e6f7g8h9i0j"
                  pix:
                    emv: "00020126580014br.gov.bcb.pix0136..."
                    qrCode: "iVBORw0KGgo..."
                  status: "pending"
                  fees: 0
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: QR Code PIX não encontrado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "NOT_FOUND"
                message: "QR Code PIX não encontrado"
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/pix/in/qrcode/{transactionId}/pay:
    post:
      tags:
        - Sandbox
      summary: Simular pagamento PIX (sandbox)
      operationId: sandbox-pix-in-pay
      description: |
        Confirma manualmente o pagamento de uma cobrança PIX criada com uma chave
        **sandbox**. Dispara o mesmo webhook `transaction_paid` que produção enviaria.

        Retorna `403 Forbidden` se a transação não pertencer a uma chave sandbox, e
        `400 Bad Request` se ela já não estiver mais `pending`.
      security:
        - bearerAuth: []
      parameters:
        - name: transactionId
          in: path
          required: true
          description: ID da transação retornado na criação do QR Code
          schema:
            type: string
            example: "trx_1a2b3c4d5e6f7g8h9i0j"
      x-codeSamples:
        - lang: Shell
          label: cURL
          source: |
            curl -X POST 'https://api.liontechpay.com/api/v1/pix/in/qrcode/trx_1a2b3c4d5e6f7g8h9i0j/pay' \
              -H 'Authorization: Bearer SEU_TOKEN_SANDBOX_AQUI'
        - lang: JavaScript
          label: Node.js
          source: |
            const transactionId = 'trx_1a2b3c4d5e6f7g8h9i0j'

            const response = await fetch(
              `https://api.liontechpay.com/api/v1/pix/in/qrcode/${transactionId}/pay`,
              {
                method: 'POST',
                headers: { 'Authorization': 'Bearer SEU_TOKEN_SANDBOX_AQUI' }
              }
            )

            const { data } = await response.json()
            console.log(data.status)
        - lang: Python
          label: Python
          source: |
            import requests

            transaction_id = 'trx_1a2b3c4d5e6f7g8h9i0j'
            response = requests.post(
                f'https://api.liontechpay.com/api/v1/pix/in/qrcode/{transaction_id}/pay',
                headers={'Authorization': 'Bearer SEU_TOKEN_SANDBOX_AQUI'}
            )

            data = response.json()['data']
            print(data['status'])
        - lang: PHP
          label: PHP
          source: |
            $transactionId = 'trx_1a2b3c4d5e6f7g8h9i0j';

            $ch = curl_init("https://api.liontechpay.com/api/v1/pix/in/qrcode/{$transactionId}/pay");
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
                'Authorization: Bearer SEU_TOKEN_SANDBOX_AQUI'
            ]);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

            $response = json_decode(curl_exec($ch), true);
      responses:
        '200':
          description: Pagamento simulado com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message:
                    type: string
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                      status:
                        type: string
                      endToEndId:
                        type: string
              example:
                success: true
                message: "Pagamento simulado com sucesso"
                data:
                  id: "trx_1a2b3c4d5e6f7g8h9i0j"
                  status: "paid"
                  endToEndId: "E0000000020260810144500ABCDE123456"
        '400':
          description: Transação não está mais pendente
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Transação não pertence a uma chave sandbox
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Transação não encontrada
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'

  # ─────────────────────────────────────────────
  # PIX OUT
  # ─────────────────────────────────────────────
  /api/v1/pix/out/pixkey:
    post:
      tags:
        - PIX OUT
      summary: Enviar transferência PIX
      operationId: pix-out-send-pixkey
      description: |
        Realiza uma **transferência PIX** para qualquer chave PIX.

        ### Tipos de chave PIX aceitos

        | Tipo | Formato | Exemplo |
        |------|---------|---------|
        | CPF | Apenas dígitos | `11122233344` |
        | CNPJ | Apenas dígitos | `11222333000181` |
        | E-mail | Email válido | `destino@email.com` |
        | Telefone | Com `+55` | `+5511999999999` |
        | Chave aleatória | UUID | `123e4567-e89b-12d3-a456-426614174000` |

        ### Idempotência obrigatória

        Envie um **UUID único** no header `x-idempotency-key` para cada nova transferência.
        Se a requisição falhar, reuse o mesmo UUID no retry — isso garante que a transferência
        não seja duplicada.

        ```
        x-idempotency-key: 550e8400-e29b-41d4-a716-446655440000
        ```

        > ⚠️ A transferência é irreversível após processamento. Verifique a chave PIX antes de enviar.
      security:
        - bearerAuth: []
      parameters:
        - name: x-idempotency-key
          in: header
          required: true
          description: UUID único para garantir que a transferência não seja duplicada em caso de retry
          schema:
            type: string
            example: "550e8400-e29b-41d4-a716-446655440000"
      x-codeSamples:
        - lang: Shell
          label: cURL
          source: |
            curl -X POST 'https://api.liontechpay.com/api/v1/pix/out/pixkey' \
              -H 'Authorization: Bearer SEU_TOKEN_AQUI' \
              -H 'Content-Type: application/json' \
              -H 'x-idempotency-key: 550e8400-e29b-41d4-a716-446655440000' \
              -d '{
                "pixKey": "fornecedor@exemplo.com",
                "amount": 10000,
                "currency": "BRL",
                "description": "Pagamento de fornecedor",
                "postbackUrl": "https://exemplo.com.br/webhook/pix-out"
              }'
        - lang: JavaScript
          label: Node.js
          source: |
            const { randomUUID } = require('crypto')

            const response = await fetch('https://api.liontechpay.com/api/v1/pix/out/pixkey', {
              method: 'POST',
              headers: {
                'Authorization': 'Bearer SEU_TOKEN_AQUI',
                'Content-Type': 'application/json',
                'x-idempotency-key': randomUUID()
              },
              body: JSON.stringify({
                pixKey: 'fornecedor@exemplo.com',
                amount: 10000,
                currency: 'BRL',
                description: 'Pagamento de fornecedor',
                postbackUrl: 'https://exemplo.com.br/webhook/pix-out'
              })
            })

            const { data } = await response.json()
            console.log(data.status) // 'queued'
        - lang: Python
          label: Python
          source: |
            import requests
            import uuid

            response = requests.post(
                'https://api.liontechpay.com/api/v1/pix/out/pixkey',
                headers={
                    'Authorization': 'Bearer SEU_TOKEN_AQUI',
                    'Content-Type': 'application/json',
                    'x-idempotency-key': str(uuid.uuid4())
                },
                json={
                    'pixKey': 'fornecedor@exemplo.com',
                    'amount': 10000,
                    'currency': 'BRL',
                    'description': 'Pagamento de fornecedor',
                    'postbackUrl': 'https://exemplo.com.br/webhook/pix-out'
                }
            )

            data = response.json()['data']
            print(data['status'])
        - lang: PHP
          label: PHP
          source: |
            $payload = json_encode([
                'pixKey' => 'fornecedor@exemplo.com',
                'amount' => 10000,
                'currency' => 'BRL',
                'description' => 'Pagamento de fornecedor',
                'postbackUrl' => 'https://exemplo.com.br/webhook/pix-out'
            ]);

            $ch = curl_init('https://api.liontechpay.com/api/v1/pix/out/pixkey');
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
                'Authorization: Bearer SEU_TOKEN_AQUI',
                'Content-Type: application/json',
                'x-idempotency-key: ' . sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
                    mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff),
                    mt_rand(0, 0x0fff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000,
                    mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff))
            ]);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

            $response = json_decode(curl_exec($ch), true);
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - pixKey
                - amount
              properties:
                pixKey:
                  type: string
                  description: Chave PIX de destino (CPF, CNPJ, email, telefone ou chave aleatória)
                  example: "fornecedor@exemplo.com"
                amount:
                  type: integer
                  minimum: 1
                  description: Valor da transferência em centavos
                  example: 10000
                currency:
                  type: string
                  description: Moeda (apenas BRL aceito)
                  default: "BRL"
                  example: "BRL"
                description:
                  type: string
                  maxLength: 140
                  description: Descrição da transferência
                  example: "Pagamento de fornecedor"
                postbackUrl:
                  type: string
                  format: uri
                  description: URL para receber notificação de status da transferência
                  example: "https://exemplo.com.br/webhook/pix-out"
            examples:
              email:
                summary: Transferência para e-mail
                value:
                  pixKey: "fornecedor@exemplo.com"
                  amount: 10000
                  currency: "BRL"
                  description: "Pagamento de fornecedor"
                  postbackUrl: "https://exemplo.com.br/webhook/pix-out"
              cpf:
                summary: Transferência para CPF
                value:
                  pixKey: "11122233344"
                  amount: 5000
                  currency: "BRL"
                  description: "Reembolso"
              chaveAleatoria:
                summary: Chave aleatória
                value:
                  pixKey: "123e4567-e89b-12d3-a456-426614174000"
                  amount: 25000
                  currency: "BRL"
      responses:
        '200':
          description: Transferência iniciada com sucesso
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PixTransferResponse'
              example:
                success: true
                message: "Transferência criada com sucesso"
                data:
                  id: "transfer_abc123def456"
                  status: "pending"
                  amount: 10000
                  netAmount: 10000
                  fees: 0
                  pixKey: "fornecedor@exemplo.com"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '409':
          description: Chave de idempotência já utilizada — operação não duplicada
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "IDEMPOTENCY_CONFLICT"
                message: "Esta chave de idempotência já foi utilizada"
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/pix/out/pixkey/{transferId}:
    get:
      tags:
        - PIX OUT
      summary: Consultar transferência PIX
      operationId: pix-out-get-pixkey
      description: |
        Consulta uma transferência PIX criada anteriormente e retorna o status atual.

        Use o `id` retornado na criação da transferência PIX OUT.
      security:
        - bearerAuth: []
      parameters:
        - name: transferId
          in: path
          required: true
          description: ID da transferência retornado na criação do PIX OUT
          schema:
            type: string
            example: "transfer_abc123def456"
      x-codeSamples:
        - lang: Shell
          label: cURL
          source: |
            curl -X GET 'https://api.liontechpay.com/api/v1/pix/out/pixkey/transfer_abc123def456' \
              -H 'Authorization: Bearer SEU_TOKEN_AQUI'
        - lang: JavaScript
          label: Node.js
          source: |
            const transferId = 'transfer_abc123def456'

            const response = await fetch(
              `https://api.liontechpay.com/api/v1/pix/out/pixkey/${transferId}`,
              {
                headers: { 'Authorization': 'Bearer SEU_TOKEN_AQUI' }
              }
            )

            const { data } = await response.json()
            console.log(data.status)
        - lang: Python
          label: Python
          source: |
            import requests

            transfer_id = 'transfer_abc123def456'
            response = requests.get(
                f'https://api.liontechpay.com/api/v1/pix/out/pixkey/{transfer_id}',
                headers={'Authorization': 'Bearer SEU_TOKEN_AQUI'}
            )

            data = response.json()['data']
            print(data['status'])
        - lang: PHP
          label: PHP
          source: |
            $transferId = 'transfer_abc123def456';

            $ch = curl_init("https://api.liontechpay.com/api/v1/pix/out/pixkey/{$transferId}");
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
                'Authorization: Bearer SEU_TOKEN_AQUI'
            ]);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

            $response = json_decode(curl_exec($ch), true);
      responses:
        '200':
          description: Transferência PIX encontrada com sucesso
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PixTransferGetResponse'
              example:
                success: true
                data:
                  id: "transfer_abc123def456"
                  status: "completed"
                  amount: 10000
                  netAmount: 10000
                  fees: 0
                  pixKey: "fornecedor@exemplo.com"
                  endToEndId: "E1234567820241231000000000000002"
                  createdAt: "2026-01-15T13:44:25.838Z"
                  updatedAt: "2026-01-15T13:45:10.120Z"
                  processedAt: "2026-01-15T13:45:10.120Z"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Transferência PIX não encontrada
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "NOT_FOUND"
                message: "Transferência não encontrada"
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/pix/out/pixkey/{transferId}/complete:
    post:
      tags:
        - Sandbox
      summary: Simular conclusão de transferência PIX (sandbox)
      operationId: sandbox-pix-out-complete
      description: |
        Confirma manualmente a conclusão de uma transferência PIX criada com uma chave
        **sandbox**. Dispara o mesmo webhook `transfer_completed` que produção enviaria.

        Assim como em produção, transferências sandbox passam pelo fluxo normal de
        aprovação antes de ficarem "em progresso" — consulte `GET /pixkey/{transferId}`
        e aguarde ela sair de `pending`/`manual_analysis` antes de chamar este endpoint.

        Retorna `403 Forbidden` se a transferência não pertencer a uma chave sandbox.
      security:
        - bearerAuth: []
      parameters:
        - name: transferId
          in: path
          required: true
          description: ID da transferência retornado na criação do PIX OUT
          schema:
            type: string
            example: "transfer_abc123def456"
      x-codeSamples:
        - lang: Shell
          label: cURL
          source: |
            curl -X POST 'https://api.liontechpay.com/api/v1/pix/out/pixkey/transfer_abc123def456/complete' \
              -H 'Authorization: Bearer SEU_TOKEN_SANDBOX_AQUI'
        - lang: JavaScript
          label: Node.js
          source: |
            const transferId = 'transfer_abc123def456'

            const response = await fetch(
              `https://api.liontechpay.com/api/v1/pix/out/pixkey/${transferId}/complete`,
              {
                method: 'POST',
                headers: { 'Authorization': 'Bearer SEU_TOKEN_SANDBOX_AQUI' }
              }
            )

            const { data } = await response.json()
            console.log(data.status)
        - lang: Python
          label: Python
          source: |
            import requests

            transfer_id = 'transfer_abc123def456'
            response = requests.post(
                f'https://api.liontechpay.com/api/v1/pix/out/pixkey/{transfer_id}/complete',
                headers={'Authorization': 'Bearer SEU_TOKEN_SANDBOX_AQUI'}
            )

            data = response.json()['data']
            print(data['status'])
        - lang: PHP
          label: PHP
          source: |
            $transferId = 'transfer_abc123def456';

            $ch = curl_init("https://api.liontechpay.com/api/v1/pix/out/pixkey/{$transferId}/complete");
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
                'Authorization: Bearer SEU_TOKEN_SANDBOX_AQUI'
            ]);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

            $response = json_decode(curl_exec($ch), true);
      responses:
        '200':
          description: Transferência concluída com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  message:
                    type: string
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                      status:
                        type: string
                      endToEndId:
                        type: string
              example:
                success: true
                message: "Transferência concluída com sucesso"
                data:
                  id: "transfer_abc123def456"
                  status: "completed"
                  endToEndId: "E0000000020260810144500ABCDE654321"
        '400':
          description: Transferência já concluída/cancelada
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          description: Transferência não pertence a uma chave sandbox
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: Transferência não encontrada
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'

  # ─────────────────────────────────────────────
  # SALDO
  # ─────────────────────────────────────────────
  /api/v1/balance:
    get:
      tags:
        - Saldo
      summary: Consultar saldo
      operationId: balance-get
      description: |
        Retorna os **saldos atuais** das carteiras da empresa autenticada.

        ### Carteiras retornadas

        | Campo | Descrição |
        |-------|-----------|
        | `pix.balance` | Saldo livre disponível para uso e transferências |
        | `pixBlocked.balance` | Saldo bloqueado por cautelar ou MED (indisponível) |
        | `reserve.balance` | Valor em reserva (aguardando liquidação) |

        > Os valores são retornados em **reais** como string com 2 casas decimais (ex: `"150.00"`).
      security:
        - bearerAuth: []
      x-codeSamples:
        - lang: Shell
          label: cURL
          source: |
            curl -X GET 'https://api.liontechpay.com/api/v1/balance' \
              -H 'Authorization: Bearer SEU_TOKEN_AQUI'
        - lang: JavaScript
          label: Node.js
          source: |
            const response = await fetch('https://api.liontechpay.com/api/v1/balance', {
              headers: { 'Authorization': 'Bearer SEU_TOKEN_AQUI' }
            })

            const { data } = await response.json()
            console.log('Saldo disponível: R$', data.pix.balance)
            console.log('Bloqueado: R$',        data.pixBlocked.balance)
            console.log('Reserva: R$',          data.reserve.balance)
        - lang: Python
          label: Python
          source: |
            import requests

            response = requests.get(
                'https://api.liontechpay.com/api/v1/balance',
                headers={'Authorization': 'Bearer SEU_TOKEN_AQUI'}
            )

            data = response.json()['data']
            print(f"Saldo disponivel: R$ {data['pix']['balance']}")
            print(f"Bloqueado:        R$ {data['pixBlocked']['balance']}")
            print(f"Reserva:          R$ {data['reserve']['balance']}")
        - lang: PHP
          label: PHP
          source: |
            $ch = curl_init('https://api.liontechpay.com/api/v1/balance');
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
                'Authorization: Bearer SEU_TOKEN_AQUI'
            ]);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

            $response = json_decode(curl_exec($ch), true);
            $saldo = $response['data']['pix']['balance'];
            echo "Saldo disponivel: R$ {$saldo}";
      responses:
        '200':
          description: Saldos retornados com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: object
                    properties:
                      pix:
                        type: object
                        properties:
                          balance:
                            type: string
                            description: Saldo disponivel em reais (2 casas decimais)
                            example: "1250.00"
                      pixBlocked:
                        type: object
                        properties:
                          balance:
                            type: string
                            description: Saldo bloqueado em reais (cautelar ou MED)
                            example: "0.00"
                      reserve:
                        type: object
                        properties:
                          balance:
                            type: string
                            description: Saldo em reserva em reais
                            example: "300.00"
              example:
                success: true
                data:
                  pix:
                    balance: "1250.00"
                  pixBlocked:
                    balance: "0.00"
                  reserve:
                    balance: "300.00"
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'

  # ─────────────────────────────────────────────
  # FORMATO DOS WEBHOOKS
  # ─────────────────────────────────────────────
  /docs/webhooks/pagamento:
    get:
      tags:
        - Formato dos Webhooks
      summary: Pagamento
      operationId: webhook-format-payment
      description: |
        Exemplo do payload enviado nos callbacks de **PIX IN**.

        Este item é apenas referência de formato. Não é uma rota da API.

        Eventos relacionados:

        | Evento | Quando é enviado |
        |--------|------------------|
        | `transaction_created` | Cobrança PIX criada |
        | `transaction_paid` | Cobrança PIX paga |
        | `transaction_refunded` | Cobrança PIX estornada |
        | `transaction_updated` | Cobrança PIX atualizada com outro status |
        | `infraction` | Infração/MED criada ou atualizada para uma cobrança PIX |
      responses:
        '200':
          description: Exemplo de payload de callback de pagamento
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookPaymentPayload'
              example:
                id: "8d0f3b8f-5c2f-4a10-8dd6-8bbf5e9b1d11"
                type: "transaction"
                event: "transaction_paid"
                scope: "user"
                transaction:
                  id: "transaction_abc123"
                  amount: 5000
                  status: "paid"
                  pix:
                    endToEndId: "E1234567820241231000000000000001"
                    payerInfo:
                      name: "Joao Silva"
                      document: "11122233344"

  /docs/webhooks/transferencia:
    get:
      tags:
        - Formato dos Webhooks
      summary: Transferência
      operationId: webhook-format-transfer
      description: |
        Exemplo do payload enviado nos callbacks de **PIX OUT**.

        Este item é apenas referência de formato. Não é uma rota da API.

        Eventos relacionados:

        | Evento | Quando é enviado |
        |--------|------------------|
        | `transfer_created` | Transferência PIX criada |
        | `transfer_updated` | Transferência PIX atualizada com outro status |
        | `transfer_completed` | Transferência PIX concluída |
        | `transfer_canceled` | Transferência PIX cancelada ou recusada |
      responses:
        '200':
          description: Exemplo de payload de callback de transferência
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookTransferPayload'
              example:
                id: "5f9e0c94-60a4-4df8-bb81-7f6efc6f61b0"
                type: "transfer"
                event: "transfer_completed"
                scope: "user"
                transfer:
                  id: "transfer_abc123"
                  amount: 10000
                  status: "paid"
                  pix:
                    endToEndId: "E1234567820241231000000000000002"
                    creditorAccount:
                      name: "Fornecedor Exemplo"
                      document: "12345678000199"

  # ─────────────────────────────────────────────
  # WEBHOOKS
  # ─────────────────────────────────────────────
  /api/v1/webhook:
    get:
      tags:
        - Webhooks
      summary: Listar webhooks
      operationId: webhooks-list
      description: |
        Retorna todos os **webhooks configurados** na sua conta.
      security:
        - bearerAuth: []
      x-codeSamples:
        - lang: Shell
          label: cURL
          source: |
            curl -X GET 'https://api.liontechpay.com/api/v1/webhook' \
              -H 'Authorization: Bearer SEU_TOKEN_AQUI'
        - lang: JavaScript
          label: Node.js
          source: |
            const response = await fetch('https://api.liontechpay.com/api/v1/webhook', {
              headers: { 'Authorization': 'Bearer SEU_TOKEN_AQUI' }
            })
            const { data } = await response.json()
            const { webhooks } = data
        - lang: Python
          label: Python
          source: |
            import requests

            response = requests.get(
                'https://api.liontechpay.com/api/v1/webhook',
                headers={'Authorization': 'Bearer SEU_TOKEN_AQUI'}
            )
            webhooks = response.json()['data']['webhooks']
        - lang: PHP
          label: PHP
          source: |
            $ch = curl_init('https://api.liontechpay.com/api/v1/webhook');
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
                'Authorization: Bearer SEU_TOKEN_AQUI'
            ]);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            $response = json_decode(curl_exec($ch), true);
            $webhooks = $response['data']['webhooks'];
      responses:
        '200':
          description: Lista de webhooks
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: object
                    properties:
                      webhooks:
                        type: array
                        items:
                          $ref: '#/components/schemas/Webhook'
                      pagination:
                        type: object
                        additionalProperties: true
              example:
                success: true
                data:
                  webhooks:
                    - id: 123
                      name: "Meu webhook"
                      url: "https://exemplo.com.br/webhook"
                      events:
                        - "transaction_paid"
                        - "transfer_completed"
                      isActive: true
                      signatureSecret: "secret_abc123"
                      mtlsCapable: false
                      createdAt: "2024-12-31T12:00:00Z"
                  pagination:
                    offset: 0
                    pageSize: 10
                    totalCount: 1
                    currentPage: 1
                    totalPages: 1
                    hasNext: false
                    hasPrevious: false
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'

    post:
      tags:
        - Webhooks
      summary: Criar webhook
      operationId: webhooks-create
      description: |
        Configura um novo **endpoint de webhook** para receber notificações de eventos.

        ### Como validar a autenticidade

        A Lion Tech Pay envia um `signatureSecret` na criação. Use-o para validar
        que as notificações são legítimas via HMAC-SHA256:

        ```javascript
        const crypto = require('crypto')

        function isValidLionWebhook(payload, signature, secret) {
          const [timestampPart, signaturePart] = signature.split(',')
          const timestamp = timestampPart.replace('t=', '')
          const receivedSignature = signaturePart.replace('v1=', '')

          const expected = crypto
            .createHmac('sha256', secret)
            .update(`${timestamp}.${JSON.stringify(payload)}`)
            .digest('hex')

          return expected === receivedSignature
        }
        ```
      security:
        - bearerAuth: []
      x-codeSamples:
        - lang: Shell
          label: cURL
          source: |
            curl -X POST 'https://api.liontechpay.com/api/v1/webhook' \
              -H 'Authorization: Bearer SEU_TOKEN_AQUI' \
              -H 'Content-Type: application/json' \
              -d '{
                "url": "https://exemplo.com.br/webhook",
                "events": ["transaction_paid", "transfer_completed"]
              }'
        - lang: JavaScript
          label: Node.js
          source: |
            const response = await fetch('https://api.liontechpay.com/api/v1/webhook', {
              method: 'POST',
              headers: {
                'Authorization': 'Bearer SEU_TOKEN_AQUI',
                'Content-Type': 'application/json'
              },
              body: JSON.stringify({
                url: 'https://exemplo.com.br/webhook',
                events: ['transaction_paid', 'transfer_completed']
              })
            })

            const webhook = await response.json()
        - lang: Python
          label: Python
          source: |
            import requests

            response = requests.post(
                'https://api.liontechpay.com/api/v1/webhook',
                headers={
                    'Authorization': 'Bearer SEU_TOKEN_AQUI',
                    'Content-Type': 'application/json'
                },
                json={
                    'url': 'https://exemplo.com.br/webhook',
                    'events': ['transaction_paid', 'transfer_completed']
                }
            )
        - lang: PHP
          label: PHP
          source: |
            $payload = json_encode([
                'url' => 'https://exemplo.com.br/webhook',
                'events' => ['transaction_paid', 'transfer_completed']
            ]);

            $ch = curl_init('https://api.liontechpay.com/api/v1/webhook');
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
                'Authorization: Bearer SEU_TOKEN_AQUI',
                'Content-Type: application/json'
            ]);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            $response = json_decode(curl_exec($ch), true);
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - url
                - events
              properties:
                url:
                  type: string
                  format: uri
                  description: URL HTTPS que receberá as notificações via POST
                  example: "https://exemplo.com.br/webhook"
                events:
                  type: array
                  minItems: 1
                  description: Eventos que devem disparar a notificação
                  items:
                    type: string
                    enum:
                      - transaction_created
                      - transaction_paid
                      - transaction_refunded
                      - transaction_updated
                      - transfer_created
                      - transfer_updated
                      - transfer_completed
                      - transfer_canceled
                      - infraction
                  example:
                    - "transaction_paid"
                    - "transfer_completed"
            examples:
              basico:
                summary: Apenas pagamentos confirmados
                value:
                  url: "https://exemplo.com.br/webhook"
                  events:
                    - "transaction_paid"
              completo:
                summary: Todos os eventos de transação e transferência
                value:
                  url: "https://exemplo.com.br/webhook"
                  events:
                    - "transaction_created"
                    - "transaction_paid"
                    - "transaction_refunded"
                    - "transaction_updated"
                    - "transfer_created"
                    - "transfer_updated"
                    - "transfer_completed"
                    - "transfer_canceled"
                    - "infraction"
      responses:
        '201':
          description: Webhook criado com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    $ref: '#/components/schemas/Webhook'
              example:
                success: true
                data:
                  id: 123
                  name: "Meu webhook"
                  url: "https://exemplo.com.br/webhook"
                  events:
                    - "transaction_paid"
                    - "transfer_completed"
                  isActive: true
                  signatureSecret: "secret_abc123"
                  mtlsCapable: false
                  createdAt: "2024-12-31T12:00:00Z"
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/webhook/{id}:
    delete:
      tags:
        - Webhooks
      summary: Deletar webhook
      operationId: webhooks-delete
      description: |
        Remove um webhook permanentemente pelo seu ID.

        > ⚠️ Esta ação é **irreversível**. O webhook deixará de receber notificações imediatamente.
      security:
        - bearerAuth: []
      parameters:
        - name: id
          in: path
          required: true
          description: ID do webhook a ser removido
          schema:
            type: string
            example: "webhook_abc123xyz"
      x-codeSamples:
        - lang: Shell
          label: cURL
          source: |
            curl -X DELETE 'https://api.liontechpay.com/api/v1/webhook/webhook_abc123xyz' \
              -H 'Authorization: Bearer SEU_TOKEN_AQUI'
        - lang: JavaScript
          label: Node.js
          source: |
            const webhookId = 'webhook_abc123xyz'

            const response = await fetch(
              `https://api.liontechpay.com/api/v1/webhook/${webhookId}`,
              {
                method: 'DELETE',
                headers: { 'Authorization': 'Bearer SEU_TOKEN_AQUI' }
              }
            )

            if (response.status === 200) {
              console.log('Webhook removido com sucesso')
            }
        - lang: Python
          label: Python
          source: |
            import requests

            webhook_id = 'webhook_abc123xyz'

            response = requests.delete(
                f'https://api.liontechpay.com/api/v1/webhook/{webhook_id}',
                headers={'Authorization': 'Bearer SEU_TOKEN_AQUI'}
            )

            if response.status_code == 200:
                print('Webhook removido com sucesso')
        - lang: PHP
          label: PHP
          source: |
            $webhookId = 'webhook_abc123xyz';

            $ch = curl_init("https://api.liontechpay.com/api/v1/webhook/{$webhookId}");
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
                'Authorization: Bearer SEU_TOKEN_AQUI'
            ]);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_exec($ch);

            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            if ($httpCode === 200) {
                echo 'Webhook removido com sucesso';
            }
      responses:
        '200':
          description: Webhook removido com sucesso
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
              example:
                success: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: Webhook não encontrado
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: "NOT_FOUND"
                message: "Webhook não encontrado"
        '429':
          $ref: '#/components/responses/RateLimited'

# ─────────────────────────────────────────────
# COMPONENTES
# ─────────────────────────────────────────────
components:
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
      description: |
        Autenticação Basic para obter o token JWT.
        Use `client_id` como usuário e `client_secret` como senha, codificados em Base64.
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        Token JWT obtido via `POST /api/auth`.
        Envie no header: `Authorization: Bearer <token>`

  responses:
    Unauthorized:
      description: Token ausente, inválido ou expirado
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: "UNAUTHORIZED"
            message: "Token de autenticação inválido ou expirado"

    BadRequest:
      description: Dados inválidos na requisição
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: "INVALID_REQUEST"
            message: "O campo 'amountInCents' é obrigatório"

    RateLimited:
      description: Limite de requisições excedido
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: "RATE_LIMITED"
            message: "Muitas requisições. Tente novamente em alguns minutos."

  schemas:
    Customer:
      type: object
      required:
        - documentType
        - document
      properties:
        name:
          type: string
          description: Nome completo do cliente
          example: "João Silva"
        email:
          type: string
          format: email
          description: E-mail do cliente
          example: "joao@exemplo.com"
        documentType:
          type: string
          enum:
            - cpf
            - cnpj
          description: Tipo do documento
          example: "cpf"
        document:
          type: string
          description: CPF (apenas dígitos) ou CNPJ (apenas dígitos)
          example: "11122233344"
        phone:
          type: string
          description: Telefone do cliente com DDD
          example: "(11) 91234-5678"
        billingAddress:
          $ref: '#/components/schemas/Address'

    Item:
      type: object
      required:
        - title
        - tangible
        - quantity
        - amountInCents
      properties:
        title:
          type: string
          description: Nome do produto ou serviço
          example: "Produto A"
        tangible:
          type: boolean
          description: Indica se o item é físico
          example: true
        quantity:
          type: integer
          minimum: 1
          description: Quantidade do item
          example: 2
        amountInCents:
          type: integer
          description: Valor do item em centavos
          example: 2500
        shippingAddress:
          $ref: '#/components/schemas/Address'

    Address:
      type: object
      properties:
        street:
          type: string
          description: Logradouro
          example: "Rua Exemplo"
        number:
          type: string
          description: Número
          example: "100"
        neighborhood:
          type: string
          description: Bairro
          example: "Centro"
        city:
          type: string
          description: Cidade
          example: "São Paulo"
        state:
          type: string
          description: UF do estado
          example: "SP"
        zipCode:
          type: string
          description: CEP
          example: "00000-000"

    PixQRCodeResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        message:
          type: string
          example: "Transação criada com sucesso"
        data:
          type: object
          properties:
            id:
              type: string
              description: ID único da transação
              example: "trx_1a2b3c4d5e6f7g8h9i0j"
            pix:
              type: object
              properties:
                emv:
                  type: string
                  description: Código EMV (copia e cola) para pagamento PIX
                  example: "00020126580014br.gov.bcb.pix..."
                qrCode:
                  type: string
                  description: Imagem do QR Code em Base64
                  example: "iVBORw0KGgo..."
            status:
              type: string
              enum:
                - pending
                - paid
                - canceled
                - refunded
              description: Status da transação
              example: "pending"
            fees:
              type: integer
              description: Taxa cobrada em centavos
              example: 0

    PixTransferResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        message:
          type: string
          example: "Transferência criada com sucesso"
        data:
          type: object
          properties:
            id:
              type: string
              description: ID único da transferência
              example: "transfer_abc123def456"
            status:
              type: string
              enum:
                - queued
                - processing
                - pending
                - pending_analysis
                - banking_processing
                - banking_refused
                - banking_error
                - manual_analysis
                - completed
                - canceled
                - refused
                - error
              description: Status da transferência
              example: "pending"
            amount:
              type: integer
              description: Valor total em centavos
              example: 10000
            netAmount:
              type: integer
              description: Valor líquido após taxas em centavos
              example: 10000
            fees:
              type: integer
              description: Taxas cobradas em centavos
              example: 0
            pixKey:
              type: string
              description: Chave PIX de destino
              example: "fornecedor@exemplo.com"

    PixTransferGetResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        data:
          type: object
          properties:
            id:
              type: string
              description: ID único da transferência
              example: "transfer_abc123def456"
            status:
              type: string
              enum:
                - pending
                - queued
                - processing
                - pending_analysis
                - banking_processing
                - banking_refused
                - banking_error
                - manual_analysis
                - canceled
                - refused
                - completed
                - error
              description: Status da transferência
              example: "completed"
            amount:
              type: integer
              description: Valor total em centavos
              example: 10000
            netAmount:
              type: integer
              description: Valor líquido após taxas em centavos
              example: 10000
            fees:
              type: integer
              description: Taxas cobradas em centavos
              example: 0
            pixKey:
              type: string
              description: Chave PIX de destino
              example: "fornecedor@exemplo.com"
            endToEndId:
              type: string
              nullable: true
              description: Identificador fim a fim do PIX quando disponível
              example: "E1234567820241231000000000000002"
            createdAt:
              type: string
              format: date-time
              example: "2026-01-15T13:44:25.838Z"
            updatedAt:
              type: string
              format: date-time
              example: "2026-01-15T13:45:10.120Z"
            processedAt:
              type: string
              format: date-time
              nullable: true
              example: "2026-01-15T13:45:10.120Z"

    Webhook:
      type: object
      properties:
        id:
          type: integer
          description: ID único do webhook
          example: 123
        name:
          type: string
          nullable: true
          description: Nome do webhook
          example: "Meu webhook"
        url:
          type: string
          format: uri
          description: URL que recebe as notificações
          example: "https://exemplo.com.br/webhook"
        events:
          type: array
          description: Lista de eventos configurados
          items:
            type: string
          example:
            - "transaction_paid"
            - "transfer_completed"
        isActive:
          type: boolean
          description: Se o webhook está ativo
          example: true
        signatureSecret:
          type: string
          nullable: true
          description: Secret usado para validar a assinatura dos callbacks
          example: "secret_abc123"
        mtlsCapable:
          type: boolean
          nullable: true
          example: false
        createdAt:
          type: string
          format: date-time
          description: Data e hora de criação
          example: "2024-12-31T12:00:00Z"

    WebhookPaymentPayload:
      type: object
      description: Payload enviado nos callbacks de PIX IN.
      properties:
        id:
          type: string
          description: ID único do disparo do webhook
          example: "8d0f3b8f-5c2f-4a10-8dd6-8bbf5e9b1d11"
        type:
          type: string
          enum:
            - transaction
          example: "transaction"
        event:
          type: string
          enum:
            - transaction_created
            - transaction_paid
            - transaction_refunded
            - transaction_updated
          example: "transaction_paid"
        scope:
          type: string
          enum:
            - user
            - postback
            - system
          example: "user"
        transaction:
          type: object
          properties:
            id:
              type: string
              example: "transaction_abc123"
            amount:
              type: integer
              description: Valor em centavos
              example: 5000
            status:
              type: string
              example: "paid"
            pix:
              type: object
              nullable: true
              properties:
                endToEndId:
                  type: string
                  nullable: true
                  example: "E1234567820241231000000000000001"
                payerInfo:
                  type: object
                  nullable: true
                  additionalProperties: true

    WebhookTransferPayload:
      type: object
      description: Payload enviado nos callbacks de PIX OUT.
      properties:
        id:
          type: string
          description: ID único do disparo do webhook
          example: "5f9e0c94-60a4-4df8-bb81-7f6efc6f61b0"
        type:
          type: string
          enum:
            - transfer
          example: "transfer"
        event:
          type: string
          enum:
            - transfer_created
            - transfer_updated
            - transfer_completed
            - transfer_canceled
          example: "transfer_completed"
        scope:
          type: string
          enum:
            - user
            - postback
            - system
          example: "user"
        transfer:
          type: object
          properties:
            id:
              type: string
              example: "transfer_abc123"
            amount:
              type: integer
              description: Valor em centavos
              example: 10000
            status:
              type: string
              example: "paid"
            pix:
              type: object
              properties:
                endToEndId:
                  type: string
                  nullable: true
                  example: "E1234567820241231000000000000002"
                creditorAccount:
                  type: object
                  nullable: true
                  additionalProperties: true

    SplitItem:
      type: object
      required:
        - email
        - percentage
      properties:
        email:
          type: string
          format: email
          description: E-mail da empresa Lion Tech Pay que receberá o split (deve ter conta ativa)
          example: "parceiro@empresa.com"
        percentage:
          type: number
          minimum: 0.01
          maximum: 100
          description: |
            Percentual do valor liquido a distribuir (0.01 a 100).
            A soma de todos os splits nao pode ultrapassar 100%.
          example: 30

    Error:
      type: object
      properties:
        error:
          type: string
          description: Código do erro
          example: "INVALID_REQUEST"
        message:
          type: string
          description: Descrição do erro
          example: "O campo 'amount' é obrigatório"
        details:
          type: object
          description: Detalhes adicionais do erro
          additionalProperties: true
