{
  "openapi": "3.1.0",
  "info": {
    "title": "API Capflux v1",
    "version": "1.0.0",
    "description": "API de entrada e consulta do Capflux (contas a pagar). Cada chave é de uma empresa e só enxerga a própria empresa. Documentos enviados pela API passam pela mesma leitura, conferências e fluxo de qualquer outro documento e contam como documento do plano. Para testar sem dados reais, use a empresa fictícia \"Sandbox\" com uma chave de teste."
  },
  "servers": [
    {
      "url": "https://api.capflux.com.br",
      "description": "Produção"
    }
  ],
  "security": [
    {
      "chave": []
    }
  ],
  "components": {
    "securitySchemes": {
      "chave": {
        "type": "http",
        "scheme": "bearer",
        "description": "Chave de API criada em Configurações › Integrações › Chaves de API (mostrada uma vez)."
      }
    },
    "schemas": {
      "Erro": {
        "type": "object",
        "required": [
          "erro"
        ],
        "properties": {
          "erro": {
            "type": "object",
            "required": [
              "codigo",
              "mensagem"
            ],
            "properties": {
              "codigo": {
                "type": "string",
                "example": "campo_obrigatorio"
              },
              "mensagem": {
                "type": "string",
                "example": "Envie pelo menos um arquivo."
              },
              "campo": {
                "type": "string",
                "example": "arquivos"
              }
            }
          }
        }
      },
      "Arquivo": {
        "type": "object",
        "required": [
          "nome",
          "conteudo_base64"
        ],
        "properties": {
          "nome": {
            "type": "string",
            "example": "nota-000123.pdf"
          },
          "conteudo_base64": {
            "type": "string",
            "description": "Conteúdo do arquivo em base64."
          },
          "tipo": {
            "type": "string",
            "example": "application/pdf",
            "description": "Opcional; o tipo é conferido pelo conteúdo."
          }
        }
      },
      "DocumentoRecebido": {
        "type": "object",
        "properties": {
          "documento_id": {
            "type": "string",
            "format": "uuid"
          },
          "situacao": {
            "type": "string",
            "example": "recebida"
          },
          "arquivos": {
            "type": "integer",
            "example": 2
          },
          "ja_recebido": {
            "type": "boolean",
            "description": "true quando é a repetição de um envio com a mesma Idempotency-Key."
          }
        }
      },
      "Card": {
        "type": "object",
        "description": "O que o ERP precisa de um card. Dado bancário do fornecedor nunca sai pela API (LGPD); ele só entra por PUT /v1/fornecedores, como alteração pendente de aprovação.",
        "properties": {
          "card_id": {
            "type": "string",
            "format": "uuid"
          },
          "codigo": {
            "type": "string",
            "example": "NF-2026-000123"
          },
          "versao": {
            "type": "integer",
            "example": 4
          },
          "etapa": {
            "type": "object",
            "properties": {
              "chave": {
                "type": "string"
              },
              "nome": {
                "type": "string"
              },
              "resultado": {
                "type": [
                  "string",
                  "null"
                ],
                "example": null
              }
            }
          },
          "empresa": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "nome": {
                "type": "string"
              },
              "cnpj": {
                "type": "string"
              }
            }
          },
          "fornecedor": {
            "type": "object",
            "properties": {
              "id": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "nome": {
                "type": "string"
              },
              "cnpj_cpf": {
                "type": "string"
              }
            }
          },
          "documento": {
            "type": "object",
            "properties": {
              "tipo": {
                "type": "string"
              },
              "numero": {
                "type": "string"
              },
              "serie": {
                "type": "string"
              },
              "chave_acesso": {
                "type": "string"
              },
              "emissao": {
                "type": "string",
                "format": "date"
              }
            }
          },
          "valores": {
            "type": "object",
            "properties": {
              "bruto": {
                "type": "number"
              },
              "liquido": {
                "type": "number"
              },
              "moeda": {
                "type": "string",
                "example": "BRL"
              }
            }
          },
          "vencimento": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "competencia": {
            "type": [
              "string",
              "null"
            ]
          },
          "boleto": {
            "type": [
              "object",
              "null"
            ],
            "properties": {
              "linha_digitavel": {
                "type": "string"
              },
              "valor": {
                "type": "number"
              },
              "vencimento": {
                "type": "string",
                "format": "date"
              }
            }
          },
          "campos": {
            "type": "object",
            "description": "Campos da empresa (classificação, centro de custo, documento no ERP etc.), pela chave do campo."
          },
          "lancado_em": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "pago_com_diferenca": {
            "type": [
              "object",
              "null"
            ],
            "description": "Último pagamento informado com valor diferente do card (valor_card, valor_pago, diferenca)."
          },
          "criado_em": {
            "type": "string",
            "format": "date-time"
          },
          "arquivos": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "arquivo_id": {
                  "type": "string",
                  "format": "uuid"
                },
                "nome": {
                  "type": "string"
                },
                "tipo": {
                  "type": "string",
                  "example": "nota"
                },
                "mime": {
                  "type": "string"
                },
                "tamanho": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "FornecedorSincronizado": {
        "type": "object",
        "properties": {
          "fornecedor": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string",
                "format": "uuid"
              },
              "cnpj_cpf": {
                "type": "string"
              },
              "nome": {
                "type": "string"
              },
              "nome_erp": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "situacao": {
                "type": "string"
              },
              "empresas": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              }
            }
          },
          "dados_pagamento": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "tipo": {
                  "type": "string",
                  "enum": [
                    "banco",
                    "pix"
                  ]
                },
                "filial_cnpj": {
                  "type": [
                    "string",
                    "null"
                  ]
                },
                "situacao": {
                  "type": "string",
                  "enum": [
                    "pendente_aprovacao",
                    "sem_mudanca"
                  ]
                },
                "alteracao_id": {
                  "type": "string",
                  "format": "uuid"
                },
                "cadastro": {
                  "type": [
                    "string",
                    "null"
                  ],
                  "description": "O que vale hoje, mascarado.",
                  "example": "Banco 341 · ag. ••34 · c/c ••••5-6"
                },
                "pedido": {
                  "type": "string",
                  "description": "O enviado, mascarado."
                }
              }
            }
          }
        }
      },
      "CardComTempos": {
        "description": "Card da consulta (cenário 8): o Card, mais atualizado_em e tempos. Na fila pronta para lançar vêm só os campos do Card.",
        "allOf": [
          {
            "$ref": "#/components/schemas/Card"
          },
          {
            "type": "object",
            "properties": {
              "atualizado_em": {
                "type": "string",
                "format": "date-time"
              },
              "tempos": {
                "type": "object",
                "description": "Tempo corrido, em segundos, calculado pelo Capflux. O relógio para na etapa final (lançado ou descartado).",
                "properties": {
                  "em_andamento": {
                    "type": "boolean"
                  },
                  "encerrado_em": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time",
                    "description": "Quando entrou na etapa final."
                  },
                  "total_segundos": {
                    "type": "integer",
                    "example": 259200
                  },
                  "por_etapa": {
                    "type": "array",
                    "description": "Etapas por onde o card passou (sem a final), na ordem da primeira entrada.",
                    "items": {
                      "type": "object",
                      "properties": {
                        "chave": {
                          "type": "string",
                          "example": "cap"
                        },
                        "nome": {
                          "type": "string"
                        },
                        "segundos": {
                          "type": "integer",
                          "example": 86400
                        },
                        "entradas": {
                          "type": "integer",
                          "example": 1,
                          "description": "Quantas vezes entrou (devolução conta de novo)."
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        ]
      },
      "Pagamento": {
        "type": "object",
        "properties": {
          "pagamento_id": {
            "type": "string",
            "format": "uuid"
          },
          "data_programada": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "data_paga": {
            "type": [
              "string",
              "null"
            ],
            "format": "date"
          },
          "valor": {
            "type": [
              "number",
              "null"
            ]
          },
          "comprovante_id": {
            "type": [
              "string",
              "null"
            ],
            "format": "uuid"
          },
          "registrado_em": {
            "type": "string",
            "format": "date-time"
          },
          "divergencia": {
            "type": [
              "object",
              "null"
            ],
            "description": "Só quando o valor pago é diferente do valor do card.",
            "properties": {
              "valor_card": {
                "type": "number",
                "example": 40843.83
              },
              "valor_pago": {
                "type": "number",
                "example": 40800
              },
              "diferenca": {
                "type": "number",
                "example": -43.83
              }
            }
          }
        }
      }
    }
  },
  "paths": {
    "/v1/eu": {
      "get": {
        "summary": "Testar a chave",
        "description": "Mostra a empresa, os escopos e o limite por minuto da chave.",
        "tags": [
          "Conexão"
        ],
        "responses": {
          "200": {
            "description": "Chave válida.",
            "content": {
              "application/json": {
                "example": {
                  "empresa_id": "00000000-0000-0000-0000-000000000000",
                  "escopos": [
                    "documents:write"
                  ],
                  "limite_por_minuto": 60,
                  "api_completa": false,
                  "somente_leitura": false
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, revogada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "429": {
            "description": "Limite de chamadas por minuto da chave (60 no Essencial, 300 no Profissional). Veja Retry-After.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos para tentar de novo."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documentos": {
      "post": {
        "summary": "Enviar documentos (nota, boleto, anexos)",
        "description": "Cenário 1. Escopo documents:write (todos os planos). Até 20 arquivos e 25 MB por envio: PDF, XML fiscal, imagem, ZIP ou Word. O documento entra na caixa de entrada como qualquer outro; o card aparece quando a leitura termina (consulte GET /v1/documentos/{id}).",
        "tags": [
          "Documentos"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Obrigatório em toda escrita. A mesma chave com o mesmo corpo devolve a mesma resposta (sem duplicar); com outro corpo, 409.",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "example": "erp-nota-000123"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "arquivos"
                ],
                "properties": {
                  "arquivos": {
                    "type": "array",
                    "minItems": 1,
                    "maxItems": 20,
                    "items": {
                      "$ref": "#/components/schemas/Arquivo"
                    }
                  },
                  "assunto": {
                    "type": "string",
                    "maxLength": 300,
                    "example": "NF 123 — Fornecedor Fictício Ltda"
                  },
                  "observacao": {
                    "type": "string",
                    "maxLength": 2000
                  }
                }
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "arquivos"
                ],
                "properties": {
                  "arquivos": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "binary"
                    }
                  },
                  "assunto": {
                    "type": "string"
                  },
                  "observacao": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Recebido; a leitura segue em segundo plano.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DocumentoRecebido"
                }
              }
            }
          },
          "400": {
            "description": "Pedido inválido (ex.: sem Idempotency-Key).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, revogada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "403": {
            "description": "Escopo insuficiente ou recurso fora do plano.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key já usada com outro pedido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "413": {
            "description": "Envio maior que 25 MB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "415": {
            "description": "Tipo de arquivo ou de corpo não aceito.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "422": {
            "description": "Campo faltando ou inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "429": {
            "description": "Limite de chamadas por minuto da chave (60 no Essencial, 300 no Profissional). Veja Retry-After.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos para tentar de novo."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        }
      }
    },
    "/v1/documentos/{id}": {
      "get": {
        "summary": "Situação de um documento enviado",
        "tags": [
          "Documentos"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Situação atual.",
            "content": {
              "application/json": {
                "example": {
                  "documento_id": "00000000-0000-0000-0000-000000000000",
                  "situacao": "virou_card",
                  "recebido_em": "2026-11-10T12:00:00Z",
                  "card_id": "00000000-0000-0000-0000-000000000001"
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, revogada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "403": {
            "description": "Escopo insuficiente ou recurso fora do plano.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "404": {
            "description": "Não existe nesta empresa.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        }
      }
    },
    "/v1/cards": {
      "get": {
        "summary": "Notas aprovadas para lançar · consultar cards",
        "description": "Escopo cards:read (Profissional). Duas leituras no mesmo endereço. Cenário 7, com pronto_para_lancar=true: os cards cuja etapa atual tem passagem de lançamento para \"lançado\" no fluxo da empresa — a fila pronta para o ERP. Adiantamento não entra: o encerramento depende de prestação de contas/compensação e é feito na tela. Cenário 8, sem pronto_para_lancar: consulta geral para BI (Power BI, Looker), com filtros de etapa, situação, período de criação e atualizado_desde (carga incremental). Cada item traz também atualizado_em e tempos: tempo corrido em segundos em cada etapa e no total, calculado pelo Capflux; o relógio para quando o card entra numa etapa final (lançado ou descartado). Paginação por cursor (ordem de criação): repita a chamada com o proximo_cursor da resposta até ele vir nulo. A fila também pode chegar por webhook.",
        "tags": [
          "Lançamento no ERP",
          "Consulta (BI)"
        ],
        "parameters": [
          {
            "name": "pronto_para_lancar",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean"
            },
            "description": "true = só a fila pronta para lançar (cenário 7; não combina com os filtros abaixo)."
          },
          {
            "name": "etapa",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Chaves de etapa separadas por vírgula (ex.: cap,triagem). Etapa que não existe = 422 etapa_desconhecida."
          },
          {
            "name": "situacao",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "em_andamento",
                "lancado",
                "descartado"
              ]
            }
          },
          {
            "name": "criado_de",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Criado a partir deste dia (horário de Brasília)."
          },
          {
            "name": "criado_ate",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            },
            "description": "Criado até este dia, inclusive."
          },
          {
            "name": "atualizado_desde",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Só cards que mudaram desde este momento (ISO 8601 com fuso). Guarde o horário da última carga e repita."
          },
          {
            "name": "limite",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            },
            "description": "Itens por página (1 a 200; padrão 50)."
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "O proximo_cursor da página anterior."
          }
        ],
        "responses": {
          "200": {
            "description": "Uma página (da fila ou da consulta). Na consulta, cada item tem também atualizado_em e tempos.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "itens": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CardComTempos"
                      }
                    },
                    "proximo_cursor": {
                      "type": [
                        "string",
                        "null"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, revogada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "403": {
            "description": "Escopo insuficiente ou recurso fora do plano.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "422": {
            "description": "Filtro, limite ou cursor inválido; etapa desconhecida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "429": {
            "description": "Limite de chamadas por minuto da chave (60 no Essencial, 300 no Profissional). Veja Retry-After.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos para tentar de novo."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        }
      }
    },
    "/v1/pedidos-pagamento": {
      "post": {
        "summary": "Criar pedido de pagamento sem nota",
        "description": "Cenário 6. Escopo requests:write (Profissional). Reembolso, adiantamento ou despesa de outro sistema viram card na Triagem, como o lançamento manual; as regras de caminho da empresa decidem dali (o tipo é a condição \"tipo de documento\"), e a resposta já traz a etapa decidida. Sem leitura por IA: os dados são os enviados. A descrição vira a primeira observação do card; o Histórico mostra \"API · <nome da chave>\". Mesmo número + tipo + favorecido = 409 pedido_duplicado com o card_id (além da Idempotency-Key). Dado bancário do favorecido não entra por aqui: vem do cadastro do fornecedor (PUT /v1/fornecedores, com aprovação na tela). Corpo em JSON (anexos em base64) ou multipart/form-data (campos soltos: tipo, favorecido_nome, favorecido_cnpj_cpf, valor, vencimento, descricao, numero, filial_cnpj, competencia; arquivos em \"anexos\").",
        "tags": [
          "Pedido de pagamento"
        ],
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Obrigatório em toda escrita. A mesma chave com o mesmo corpo devolve a mesma resposta (sem duplicar); com outro corpo, 409.",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "example": "erp-nota-000123"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "tipo",
                  "favorecido",
                  "valor",
                  "descricao"
                ],
                "properties": {
                  "tipo": {
                    "type": "string",
                    "enum": [
                      "reembolso",
                      "adiantamento",
                      "despesa"
                    ]
                  },
                  "favorecido": {
                    "type": "object",
                    "required": [
                      "nome"
                    ],
                    "properties": {
                      "nome": {
                        "type": "string",
                        "example": "Pessoa Fictícia"
                      },
                      "cnpj_cpf": {
                        "type": "string",
                        "example": "12345678909"
                      }
                    }
                  },
                  "valor": {
                    "type": "number",
                    "example": 150.4
                  },
                  "vencimento": {
                    "type": "string",
                    "format": "date"
                  },
                  "descricao": {
                    "type": "string",
                    "minLength": 5,
                    "maxLength": 5000,
                    "example": "Táxi para visita ao cliente"
                  },
                  "numero": {
                    "type": "string",
                    "maxLength": 60,
                    "description": "Número do pedido no sistema de origem.",
                    "example": "RB-2026-0042"
                  },
                  "filial_cnpj": {
                    "type": "string",
                    "description": "CNPJ da filial que paga (precisa existir na empresa)."
                  },
                  "competencia": {
                    "type": "string",
                    "pattern": "^\\d{4}-\\d{2}$",
                    "example": "2026-11"
                  },
                  "anexos": {
                    "type": "array",
                    "maxItems": 5,
                    "items": {
                      "type": "object",
                      "required": [
                        "nome",
                        "conteudo_base64"
                      ],
                      "properties": {
                        "nome": {
                          "type": "string"
                        },
                        "conteudo_base64": {
                          "type": "string"
                        },
                        "tipo": {
                          "type": "string",
                          "example": "application/pdf"
                        }
                      }
                    },
                    "description": "Recibo, comprovante ou autorização: PDF ou imagem, até 10 MB cada."
                  }
                }
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Card criado (com a etapa já decidida pelas regras).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Card"
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, revogada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "403": {
            "description": "Escopo insuficiente ou recurso fora do plano.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "409": {
            "description": "pedido_duplicado (com card_id) ou Idempotency-Key reaproveitada com outro corpo.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "413": {
            "description": "Anexo acima de 10 MB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "415": {
            "description": "Anexo que não é PDF nem imagem.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "422": {
            "description": "Campo faltando ou inválido; filial_desconhecida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "429": {
            "description": "Limite de chamadas por minuto da chave (60 no Essencial, 300 no Profissional). Veja Retry-After.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos para tentar de novo."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        }
      }
    },
    "/v1/fornecedores/{cnpj_cpf}": {
      "put": {
        "summary": "Sincronizar um fornecedor",
        "description": "Cenário 4. Escopo suppliers:write (Profissional). Cria ou atualiza o fornecedor pelo CNPJ/CPF do endereço (com ou sem pontuação). O cadastro (nome, nome_erp, situacao e, por filial, codigo_erp, prazo_pagamento_dias, email_cobranca) entra direto; o que não vier não muda. Conta bancária e Pix NUNCA entram direto: cada item de dados_pagamento vira alteração pendente, que alguém com permissão de alterar dado bancário aprova ou recusa na tela de Fornecedores, sempre com motivo. Até a aprovação, vale o cadastro anterior; os administradores recebem um aviso. Reenviar o mesmo dado não abre outra pendência; dado diferente substitui a pendência anterior. Depois de aprovada, a troca liga o alerta de segurança \"dados bancários alterados há pouco\" nos cards do fornecedor por 30 dias: o lançamento pela API responde 422 requer_confirmacao_na_tela até uma pessoa conferir. A resposta traz só o dado mascarado (últimos dígitos). Tudo ou nada: com um item inválido, nada é gravado.",
        "tags": [
          "Fornecedores"
        ],
        "parameters": [
          {
            "name": "cnpj_cpf",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "11222333000181"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Obrigatório em toda escrita. A mesma chave com o mesmo corpo devolve a mesma resposta (sem duplicar); com outro corpo, 409.",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "example": "erp-nota-000123"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "nome": {
                    "type": "string",
                    "description": "Razão social. Obrigatório para fornecedor novo.",
                    "example": "Fornecedor Fictício Ltda"
                  },
                  "nome_erp": {
                    "type": "string"
                  },
                  "situacao": {
                    "type": "string",
                    "enum": [
                      "ativo",
                      "inativo"
                    ]
                  },
                  "empresas": {
                    "type": "array",
                    "description": "Dados por filial (filial_cnpj nulo = todas as empresas do grupo).",
                    "items": {
                      "type": "object",
                      "properties": {
                        "filial_cnpj": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "codigo_erp": {
                          "type": "string",
                          "example": "F001"
                        },
                        "prazo_pagamento_dias": {
                          "type": "integer",
                          "minimum": 0,
                          "maximum": 365
                        },
                        "email_cobranca": {
                          "type": "string"
                        }
                      }
                    }
                  },
                  "dados_pagamento": {
                    "type": "array",
                    "maxItems": 20,
                    "description": "Fica pendente de aprovação na tela.",
                    "items": {
                      "oneOf": [
                        {
                          "type": "object",
                          "required": [
                            "tipo",
                            "banco",
                            "agencia",
                            "conta"
                          ],
                          "properties": {
                            "tipo": {
                              "const": "banco"
                            },
                            "filial_cnpj": {
                              "type": [
                                "string",
                                "null"
                              ]
                            },
                            "banco": {
                              "type": "string",
                              "example": "341"
                            },
                            "agencia": {
                              "type": "string",
                              "example": "1234"
                            },
                            "conta": {
                              "type": "string",
                              "example": "12345-6"
                            },
                            "tipo_conta": {
                              "type": "string",
                              "enum": [
                                "corrente",
                                "poupanca",
                                "pagamento"
                              ]
                            }
                          }
                        },
                        {
                          "type": "object",
                          "required": [
                            "tipo",
                            "tipo_chave",
                            "chave"
                          ],
                          "properties": {
                            "tipo": {
                              "const": "pix"
                            },
                            "filial_cnpj": {
                              "type": [
                                "string",
                                "null"
                              ]
                            },
                            "tipo_chave": {
                              "type": "string",
                              "enum": [
                                "cpf_cnpj",
                                "email",
                                "telefone",
                                "aleatoria"
                              ]
                            },
                            "chave": {
                              "type": "string"
                            }
                          }
                        }
                      ]
                    }
                  },
                  "motivo": {
                    "type": "string",
                    "maxLength": 500,
                    "description": "Mostrado a quem aprova (ex.: \"conta nova informada pelo fornecedor\")."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Atualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FornecedorSincronizado"
                }
              }
            }
          },
          "201": {
            "description": "Criado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FornecedorSincronizado"
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, revogada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "403": {
            "description": "Escopo insuficiente ou recurso fora do plano.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "415": {
            "description": "Corpo que não é JSON.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "422": {
            "description": "Campo inválido (com o campo, ex.: dados_pagamento[0]); filial_desconhecida; nome faltando para fornecedor novo.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "429": {
            "description": "Limite de chamadas por minuto da chave (60 no Essencial, 300 no Profissional). Veja Retry-After.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos para tentar de novo."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        }
      }
    },
    "/v1/cards/{id}": {
      "get": {
        "summary": "Um card",
        "description": "Escopo cards:read (Profissional). Os mesmos dados de um item da fila, inclusive a versao para enviar nas escritas.",
        "tags": [
          "Lançamento no ERP"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "O card.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Card"
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, revogada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "403": {
            "description": "Escopo insuficiente ou recurso fora do plano.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "404": {
            "description": "Não existe nesta empresa.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        }
      }
    },
    "/v1/arquivos/{id}": {
      "get": {
        "summary": "Baixar um arquivo do card",
        "description": "Escopo cards:read (Profissional). O arquivo_id vem na lista \"arquivos\" do card (nota, XML, boleto, anexos).",
        "tags": [
          "Lançamento no ERP"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "O arquivo, com o tipo e o nome no cabeçalho."
          },
          "401": {
            "description": "Chave ausente, inválida, revogada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "403": {
            "description": "Escopo insuficiente ou recurso fora do plano.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "404": {
            "description": "Não existe nesta empresa.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        }
      }
    },
    "/v1/cards/{id}/lancamento": {
      "post": {
        "summary": "Confirmar o lançamento no ERP",
        "description": "Cenário 2. Escopo erp:write (Profissional). Informe o número e a data do documento no ERP: o card segue para \"lançado\" pela mesma passagem da tela, com os mesmos campos obrigatórios, e o Histórico mostra \"API · <nome da chave>\". Adiantamento não é lançado pela API (422 nao_pronto_para_lancar com a etapa): o encerramento depende de prestação de contas e é feito na tela. Alerta comum do pagamento (possível duplicada) pede a justificativa no campo justificativa. Alerta de SEGURANÇA do pagamento (dados bancários do fornecedor alterados há pouco, beneficiário do boleto diferente do fornecedor, boleto suspeito) nunca é liberado pela API: a resposta é 422 requer_confirmacao_na_tela e o card espera uma pessoa conferir na tela; depois disso, reenvie com outra Idempotency-Key.",
        "tags": [
          "Lançamento no ERP"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Obrigatório em toda escrita. A mesma chave com o mesmo corpo devolve a mesma resposta (sem duplicar); com outro corpo, 409.",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "example": "erp-nota-000123"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "numero_documento",
                  "data_lancamento"
                ],
                "properties": {
                  "numero_documento": {
                    "type": "string",
                    "maxLength": 100,
                    "example": "5100001234"
                  },
                  "data_lancamento": {
                    "type": "string",
                    "format": "date",
                    "example": "2026-11-10"
                  },
                  "vencimento_erp": {
                    "type": "string",
                    "format": "date",
                    "example": "2026-11-30",
                    "description": "Vencimento lançado no ERP, quando o fluxo pede."
                  },
                  "justificativa": {
                    "type": "string",
                    "maxLength": 2000,
                    "description": "Só para alerta comum do pagamento (possível duplicada)."
                  },
                  "versao": {
                    "type": "integer",
                    "description": "Opcional. Se vier e o card tiver mudado, 409 card_mudou."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Lançado. Devolve o card atualizado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Card"
                }
              }
            }
          },
          "400": {
            "description": "Pedido inválido (ex.: sem Idempotency-Key).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, revogada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "403": {
            "description": "Escopo insuficiente ou recurso fora do plano.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "404": {
            "description": "Card não existe nesta empresa.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "409": {
            "description": "card_mudou (a versao enviada não é a atual) ou Idempotency-Key reutilizada.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "422": {
            "description": "nao_pronto_para_lancar ou ja_lancado (com a etapa atual); campos_obrigatorios (lista em campos: complete na tela); justificativa_obrigatoria; requer_confirmacao_na_tela (alerta de segurança: só uma pessoa libera).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "429": {
            "description": "Limite de chamadas por minuto da chave (60 no Essencial, 300 no Profissional). Veja Retry-After.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos para tentar de novo."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        }
      }
    },
    "/v1/cards/{id}/pagamento": {
      "post": {
        "summary": "Informar o pagamento",
        "description": "Cenário 3. Escopo payments:write (Profissional). Só para card lançado. Data programada e/ou data paga, valor e comprovante (PDF ou imagem, até 10 MB) opcionais. Cada envio fica registrado (nada se apaga); vale o mais recente. Alimenta o Portal do Fornecedor. Valor diferente do card (líquido; sem líquido, o bruto) é aceito — o ERP manda o que pagou —, mas a resposta traz divergencia (valor_card, valor_pago, diferenca = pago − card), o Histórico registra e o card ganha o selo \"Pago com diferença\". Um pagamento seguinte com o valor certo tira o selo.",
        "tags": [
          "Pagamento"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "Obrigatório em toda escrita. A mesma chave com o mesmo corpo devolve a mesma resposta (sem duplicar); com outro corpo, 409.",
            "schema": {
              "type": "string",
              "maxLength": 200
            },
            "example": "erp-nota-000123"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data_programada": {
                    "type": "string",
                    "format": "date",
                    "example": "2026-11-20"
                  },
                  "data_paga": {
                    "type": "string",
                    "format": "date",
                    "example": "2026-11-20"
                  },
                  "valor": {
                    "type": "number",
                    "example": 1234.56
                  },
                  "observacao": {
                    "type": "string",
                    "maxLength": 2000
                  },
                  "comprovante": {
                    "$ref": "#/components/schemas/Arquivo"
                  },
                  "versao": {
                    "type": "integer"
                  }
                }
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "data_programada": {
                    "type": "string"
                  },
                  "data_paga": {
                    "type": "string"
                  },
                  "valor": {
                    "type": "number"
                  },
                  "observacao": {
                    "type": "string"
                  },
                  "comprovante": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Registrado.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Pagamento"
                }
              }
            }
          },
          "400": {
            "description": "Pedido inválido (ex.: sem Idempotency-Key).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "401": {
            "description": "Chave ausente, inválida, revogada ou vencida.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "403": {
            "description": "Escopo insuficiente ou recurso fora do plano.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "404": {
            "description": "Card não existe nesta empresa.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "409": {
            "description": "Idempotency-Key já usada com outro pedido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "413": {
            "description": "Comprovante maior que 10 MB.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "415": {
            "description": "Comprovante que não é PDF nem imagem.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "422": {
            "description": "card_nao_lancado (com a etapa atual) ou campo faltando/inválido.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          },
          "429": {
            "description": "Limite de chamadas por minuto da chave (60 no Essencial, 300 no Profissional). Veja Retry-After.",
            "headers": {
              "Retry-After": {
                "schema": {
                  "type": "integer"
                },
                "description": "Segundos para tentar de novo."
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Erro"
                }
              }
            }
          }
        }
      }
    }
  }
}