{
  "openapi": "3.0.3",
  "info": {
    "title": "portí NFS-e — API de integração",
    "version": "1.5.0",
    "description": "Emissão de NFS-e (padrão nacional) para sistemas da Portí. Fluxo: `POST /api/v1/nfse` cria o documento fiscal a partir de um evento de negócio (idempotente por `sourceType`+`sourceId`) e dispara a emissão. O resultado chega por webhook (`callbackUrl`) ou consulta `GET /api/v1/nfse/{id}`.\n\n**Autenticação:** header `X-Api-Key: <chave>` (ou `Authorization: Bearer <chave>`). Escopos: `nfse:issue`, `nfse:read`, `admin`.\n\n**Webhook:** POST JSON no `callbackUrl` com headers `X-Nfse-Event` (`nfse.authorized` | `nfse.rejected` | `nfse.unknown`), `X-Nfse-Delivery`, `X-Nfse-Document` e `X-Nfse-Signature: sha256=<hmac-sha256 hex do corpo com o webhookSecret do cliente>`. Responda 2xx; caso contrário há retry com backoff (até 8 tentativas).\n\n**Estados:** DRAFT → VALIDATED → SIGNED → SENDING → (PROCESSING, provedor municipal) → AUTHORIZED | REJECTED | UNKNOWN (reconciliação automática) → CANCELLED.\n\n**Provedores:** o emitente define `provider` = `national` (SEFIN Nacional, municípios habilitados) ou `focus` (Focus NFe para municípios com sistema próprio). A API é a mesma.\n\n**Certificado:** cada prestador assina com o certificado digital A1 do próprio CNPJ. A SEFIN recusa DPS assinada por terceiro (rejeição E0718) e a Focus recusa o cadastro da empresa com certificado de outro CNPJ, então não há emissão por procuração de contador.\n\n**Competência:** a competência da NFS-e é sempre a data da emissão. O campo `competenceDate` do pedido é opcional e só ocupa o registro até a nota sair.\n\n**Tomador:** pessoa jurídica (CNPJ) ou pessoa física (CPF), com ou sem endereço. O documento pode ser enviado com pontuação.\n\n**Retenções:** o emitente define os percentuais e a regra por tipo de tomador; cada unidade tomadora pode declarar o que retém (`customer.retencoes`), e essa declaração prevalece sobre a regra do emitente. Valor informado explicitamente na nota vence os dois."
  },
  "servers": [
    {
      "url": "https://nfse.porti.digital",
      "description": "produção"
    },
    {
      "url": "/",
      "description": "mesma origem"
    }
  ],
  "components": {
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Api-Key"
      }
    },
    "schemas": {
      "Address": {
        "type": "object",
        "required": [
          "cityIbgeCode",
          "cep",
          "street",
          "number",
          "district"
        ],
        "properties": {
          "cityIbgeCode": {
            "type": "string",
            "example": "3550308"
          },
          "cep": {
            "type": "string",
            "example": "01310100"
          },
          "street": {
            "type": "string"
          },
          "number": {
            "type": "string"
          },
          "complement": {
            "type": "string"
          },
          "district": {
            "type": "string"
          }
        }
      },
      "Customer": {
        "type": "object",
        "required": [
          "taxIdType",
          "name"
        ],
        "properties": {
          "taxIdType": {
            "type": "string",
            "enum": [
              "CNPJ",
              "CPF",
              "NIF",
              "NONE"
            ],
            "description": "CPF para pessoa física. NIF e NONE são para tomador no exterior."
          },
          "taxId": {
            "type": "string",
            "description": "CNPJ (14 dígitos) ou CPF (11 dígitos). Pode vir formatado: a pontuação é removida. Os dígitos verificadores são conferidos.",
            "example": "11144477735"
          },
          "cNaoNIF": {
            "type": "string",
            "enum": [
              "0",
              "1",
              "2"
            ],
            "description": "motivo de não informar NIF (taxIdType=NONE)"
          },
          "name": {
            "type": "string",
            "maxLength": 300
          },
          "im": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "phone": {
            "type": "string"
          },
          "address": {
            "$ref": "#/components/schemas/Address",
            "description": "Opcional. A NFS-e aceita tomador pessoa física sem endereço."
          },
          "retencoes": {
            "$ref": "#/components/schemas/RetencoesTomador"
          }
        }
      },
      "FiscalOverrides": {
        "type": "object",
        "description": "Sobrescritas explícitas da configuração fiscal do emitente (nada é deduzido).",
        "properties": {
          "cTribNac": {
            "type": "string"
          },
          "cTribMun": {
            "type": "string"
          },
          "cNBS": {
            "type": "string"
          },
          "tribISSQN": {
            "type": "string",
            "enum": [
              "1",
              "2",
              "3",
              "4"
            ]
          },
          "tpRetISSQN": {
            "type": "string",
            "enum": [
              "1",
              "2",
              "3"
            ]
          },
          "pAliq": {
            "type": "string"
          },
          "cLocPrestacao": {
            "type": "string"
          },
          "xInfComp": {
            "type": "string"
          },
          "xPed": {
            "type": "string"
          },
          "docRef": {
            "type": "string"
          },
          "vDescIncond": {
            "type": "string"
          },
          "vDescCond": {
            "type": "string"
          },
          "ibscbs": {
            "$ref": "#/components/schemas/IbsCbs"
          }
        }
      },
      "IssueRequest": {
        "type": "object",
        "required": [
          "issuerCode",
          "sourceType",
          "sourceId",
          "serviceDescription",
          "grossValue",
          "customer"
        ],
        "properties": {
          "issuerCode": {
            "type": "string",
            "example": "PORTI"
          },
          "sourceType": {
            "type": "string",
            "example": "invoice",
            "description": "tipo do evento de negócio (idempotência)"
          },
          "sourceId": {
            "type": "string",
            "example": "INV-2026-09-0001",
            "description": "id do evento no sistema de origem (idempotência)"
          },
          "mode": {
            "type": "string",
            "enum": [
              "async",
              "sync"
            ],
            "default": "async",
            "description": "sync espera a resposta da SEFIN na mesma chamada"
          },
          "customerId": {
            "type": "string"
          },
          "competenceDate": {
            "type": "string",
            "format": "date",
            "example": "2026-09-23",
            "description": "Opcional e informativo. A competência da NFS-e é sempre a data em que a nota é emitida; se enviada, serve apenas como referência até a emissão."
          },
          "serviceDescription": {
            "type": "string",
            "maxLength": 2000
          },
          "grossValue": {
            "type": "string",
            "example": "1500.00",
            "description": "decimal com ponto e 2 casas"
          },
          "serviceCodeNational": {
            "type": "string",
            "description": "cTribNac (6 dígitos); padrão = do emitente"
          },
          "serviceCodeMunicipal": {
            "type": "string"
          },
          "nbsCode": {
            "type": "string"
          },
          "customer": {
            "$ref": "#/components/schemas/Customer"
          },
          "fiscalOverrides": {
            "$ref": "#/components/schemas/FiscalOverrides"
          },
          "callbackUrl": {
            "type": "string",
            "format": "uri",
            "description": "webhook deste documento (senão o default do cliente)"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true,
            "description": "devolvido nas consultas e webhooks"
          }
        }
      },
      "Document": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "DRAFT",
              "VALIDATED",
              "SIGNED",
              "SENDING",
              "PROCESSING",
              "AUTHORIZED",
              "REJECTED",
              "UNKNOWN",
              "CANCELLED"
            ]
          },
          "environment": {
            "type": "string",
            "enum": [
              "restricted",
              "production"
            ]
          },
          "issuerCode": {
            "type": "string"
          },
          "sourceType": {
            "type": "string"
          },
          "sourceId": {
            "type": "string"
          },
          "customerId": {
            "type": "string",
            "nullable": true
          },
          "competenceDate": {
            "type": "string",
            "description": "Competência da NFS-e. Depois da emissão, é sempre a data de emissão."
          },
          "grossValue": {
            "type": "string"
          },
          "serie": {
            "type": "string",
            "nullable": true
          },
          "dpsNumber": {
            "type": "string",
            "nullable": true
          },
          "dpsId": {
            "type": "string",
            "nullable": true
          },
          "accessKey": {
            "type": "string",
            "nullable": true,
            "description": "chave de acesso da NFS-e (50 dígitos)"
          },
          "nfseNumber": {
            "type": "string",
            "nullable": true
          },
          "issuedAt": {
            "type": "string",
            "nullable": true
          },
          "processedAt": {
            "type": "string",
            "nullable": true
          },
          "rejection": {
            "type": "object",
            "nullable": true,
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "errors": {
                "type": "array",
                "items": {
                  "type": "object"
                }
              }
            }
          },
          "lastError": {
            "type": "string",
            "nullable": true
          },
          "metadata": {
            "type": "object",
            "nullable": true
          },
          "links": {
            "type": "object",
            "properties": {
              "self": {
                "type": "string"
              },
              "xml": {
                "type": "string",
                "nullable": true
              },
              "signedDps": {
                "type": "string",
                "nullable": true
              },
              "pdf": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "createdAt": {
            "type": "string"
          },
          "updatedAt": {
            "type": "string"
          },
          "provider": {
            "type": "string",
            "enum": [
              "national",
              "focus"
            ],
            "description": "national = SEFIN Nacional direto; focus = Focus NFe (sistema municipal)"
          },
          "providerRef": {
            "type": "string",
            "nullable": true
          },
          "verificationCode": {
            "type": "string",
            "nullable": true,
            "description": "código de verificação (notas municipais)"
          },
          "cancelledAt": {
            "type": "string",
            "nullable": true
          },
          "ibsCbsNaNfse": {
            "type": "string",
            "nullable": true,
            "description": "Informativo: os valores de IBS/CBS, quando a SEFIN passar a devolvê-los, aparecem no XML autorizado (GET /nfse/{id}/xml)."
          }
        }
      },
      "WebhookPayload": {
        "type": "object",
        "properties": {
          "event": {
            "type": "string",
            "enum": [
              "nfse.authorized",
              "nfse.rejected",
              "nfse.unknown",
              "nfse.cancelled"
            ]
          },
          "deliveryAt": {
            "type": "string"
          },
          "document": {
            "$ref": "#/components/schemas/Document"
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "sefinCode": {
            "type": "string"
          },
          "issues": {
            "type": "array",
            "items": {
              "type": "object"
            }
          }
        }
      },
      "IbsCbs": {
        "type": "object",
        "description": "Destaque de IBS/CBS na DPS: apenas situação e classificação tributária. Os valores e as alíquotas de IBS e CBS são calculados pela SEFIN e aparecem na NFS-e devolvida, não são enviados aqui. Grupo opcional no layout 1.01.",
        "required": [
          "finNFSe",
          "cIndOp",
          "indDest",
          "CST",
          "cClassTrib"
        ],
        "properties": {
          "finNFSe": {
            "type": "string",
            "description": "Finalidade da emissão (1 dígito).",
            "example": "0"
          },
          "indFinal": {
            "type": "string",
            "enum": [
              "0",
              "1"
            ],
            "description": "Uso ou consumo pessoal (art. 57)."
          },
          "cIndOp": {
            "type": "string",
            "description": "Código indicador da operação de fornecimento (6 dígitos).",
            "example": "000001"
          },
          "tpOper": {
            "type": "string",
            "description": "Tipo de operação com entes governamentais ou bens imóveis."
          },
          "tpEnteGov": {
            "type": "string",
            "description": "Tipo de ente governamental."
          },
          "indDest": {
            "type": "string",
            "enum": [
              "0",
              "1"
            ],
            "description": "Indicador do destinatário dos serviços."
          },
          "CST": {
            "type": "string",
            "description": "Código de situação tributária do IBS/CBS (3 dígitos).",
            "example": "000"
          },
          "cClassTrib": {
            "type": "string",
            "description": "Código de classificação tributária do IBS/CBS (6 dígitos).",
            "example": "000001"
          },
          "cCredPres": {
            "type": "string",
            "description": "Código do crédito presumido (2 dígitos)."
          },
          "gTribRegular": {
            "type": "object",
            "properties": {
              "CSTReg": {
                "type": "string"
              },
              "cClassTribReg": {
                "type": "string"
              }
            },
            "description": "Tributação regular, quando exigida."
          },
          "gDif": {
            "type": "object",
            "properties": {
              "pDifUF": {
                "type": "string"
              },
              "pDifMun": {
                "type": "string"
              },
              "pDifCBS": {
                "type": "string"
              }
            },
            "description": "Percentuais de diferimento."
          }
        }
      },
      "RetencoesTomador": {
        "type": "object",
        "description": "Retenções que a unidade tomadora faz ao pagar a nota. Mantido por quem cadastra as unidades. Campo ausente = a unidade segue a regra do emitente. Os percentuais vêm sempre do emitente.",
        "properties": {
          "pis": {
            "type": "boolean"
          },
          "cofins": {
            "type": "boolean"
          },
          "irrf": {
            "type": "boolean"
          },
          "csll": {
            "type": "boolean"
          },
          "iss": {
            "type": "boolean",
            "description": "true envia a NFS-e com ISS retido pelo tomador."
          }
        },
        "example": {
          "pis": true,
          "cofins": true,
          "irrf": true,
          "csll": true,
          "iss": true
        }
      }
    }
  },
  "security": [
    {
      "ApiKey": []
    }
  ],
  "paths": {
    "/api/v1/nfse": {
      "post": {
        "summary": "Solicitar emissão de NFS-e",
        "tags": [
          "NFS-e"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IssueRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Documento criado e emissão enfileirada (mode=async)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          },
          "200": {
            "description": "Já existia para a origem (deduplicated=true) ou resultado síncrono (mode=sync, com `outcome`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          },
          "400": {
            "description": "Dados inválidos",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Escopo/emitente não permitido"
          },
          "404": {
            "description": "Emitente inexistente"
          },
          "422": {
            "description": "Rejeição fiscal ou XSD (mode=sync)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "Registro de NFS-e do cliente (filtros, paginação e totais)",
        "tags": [
          "NFS-e"
        ],
        "parameters": [
          {
            "name": "issuer",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "código do emitente"
          },
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "lista separada por vírgula: AUTHORIZED,REJECTED,CANCELLED,PROCESSING,UNKNOWN…"
          },
          {
            "name": "provider",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "national | focus"
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "competência inicial (AAAA-MM-DD)"
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "competência final"
          },
          {
            "name": "issuedFrom",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "emissão inicial"
          },
          {
            "name": "issuedTo",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "emissão final"
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "número da NFS-e, chave, Id da DPS, origem, tomador ou descrição"
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "padrão 50, máx. 500"
          },
          {
            "name": "offset",
            "in": "query",
            "schema": {
              "type": "integer"
            },
            "description": "paginação"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "items": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Document"
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "totals": {
                      "type": "object",
                      "properties": {
                        "count": {
                          "type": "integer"
                        },
                        "grossValue": {
                          "type": "string"
                        },
                        "authorizedValue": {
                          "type": "string"
                        },
                        "authorized": {
                          "type": "integer"
                        },
                        "rejected": {
                          "type": "integer"
                        },
                        "cancelled": {
                          "type": "integer"
                        },
                        "inProgress": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/nfse/by-source/{sourceType}/{sourceId}": {
      "get": {
        "summary": "Consultar por origem",
        "tags": [
          "NFS-e"
        ],
        "parameters": [
          {
            "name": "sourceType",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sourceId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "issuer",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          },
          "404": {
            "description": "Não encontrado"
          }
        }
      }
    },
    "/api/v1/nfse/{id}/xml": {
      "get": {
        "summary": "XML da NFS-e autorizada (ou ?type=signed para a DPS assinada)",
        "tags": [
          "NFS-e"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "type",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "authorized",
                "signed"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "XML",
            "content": {
              "application/xml": {}
            }
          },
          "404": {
            "description": "Indisponível"
          }
        }
      }
    },
    "/api/v1/nfse/{id}/pdf": {
      "get": {
        "summary": "DANFSE em PDF",
        "tags": [
          "NFS-e"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "PDF",
            "content": {
              "application/pdf": {}
            }
          },
          "404": {
            "description": "Ainda não autorizada"
          }
        }
      }
    },
    "/api/v1/nfse/{id}": {
      "get": {
        "summary": "Consultar status",
        "tags": [
          "NFS-e"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          },
          "404": {
            "description": "Não encontrado"
          }
        }
      },
      "patch": {
        "summary": "Corrigir dados de documento não autorizado (ex.: após rejeição) mantendo o mesmo Id da DPS",
        "tags": [
          "NFS-e"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IssueRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Atualizado",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          },
          "409": {
            "description": "Estado não permite"
          }
        }
      }
    },
    "/api/v1/nfse/{id}/issue": {
      "post": {
        "summary": "(Re)disparar emissão de documento existente (DRAFT/SIGNED/REJECTED/UNKNOWN); body {\"mode\":\"sync\"} espera a SEFIN",
        "tags": [
          "NFS-e"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Enfileirado"
          },
          "200": {
            "description": "Resultado síncrono",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          },
          "409": {
            "description": "Estado não permite"
          }
        }
      }
    },
    "/api/v1/nfse/{id}/reconcile": {
      "post": {
        "summary": "Reconciliar documento em UNKNOWN",
        "tags": [
          "NFS-e"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "202": {
            "description": "Enfileirado"
          }
        }
      }
    },
    "/api/v1/nfse/{id}/webhooks": {
      "get": {
        "summary": "Entregas de webhook do documento",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/api/v1/issuers": {
      "get": {
        "summary": "Emitentes disponíveis para o cliente",
        "tags": [
          "Emitentes"
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/api/v1/clients": {
      "get": {
        "summary": "Listar clientes de integração (admin)",
        "tags": [
          "Admin"
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      },
      "post": {
        "summary": "Criar cliente e chave (admin) — a chave e o webhookSecret aparecem uma única vez",
        "tags": [
          "Admin"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "scopes"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "scopes": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "nfse:issue",
                        "nfse:read",
                        "admin"
                      ]
                    }
                  },
                  "issuerCodes": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "nullable": true
                  },
                  "defaultCallbackUrl": {
                    "type": "string",
                    "nullable": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Criado"
          }
        }
      }
    },
    "/api/v1/clients/{id}": {
      "patch": {
        "summary": "Ativar/desativar cliente (admin)",
        "tags": [
          "Admin"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "active": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/api/v1/nfse/{id}/cancel": {
      "post": {
        "summary": "Cancelar NFS-e (evento 101101 no padrão nacional; cancelamento na prefeitura pela Focus)",
        "tags": [
          "NFS-e"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "justificativa"
                ],
                "properties": {
                  "justificativa": {
                    "type": "string",
                    "minLength": 15,
                    "maxLength": 255
                  },
                  "motivo": {
                    "type": "string",
                    "enum": [
                      "1",
                      "2",
                      "9"
                    ],
                    "default": "1",
                    "description": "1 erro na emissão, 2 serviço não prestado, 9 outros"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Cancelada",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Document"
                }
              }
            }
          },
          "409": {
            "description": "Estado não permite"
          },
          "501": {
            "description": "Cancelamento nacional não habilitado"
          }
        }
      }
    },
    "/api/v1/nfse/{id}/events": {
      "get": {
        "summary": "Eventos da NFS-e (histórico local + eventos registrados na SEFIN)",
        "tags": [
          "NFS-e"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/api/v1/monitor": {
      "get": {
        "summary": "Saúde da emissão (para monitoramento externo)",
        "tags": [
          "Monitoramento"
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "healthy": {
                      "type": "boolean",
                      "description": "false quando há alerta crítico aberto"
                    },
                    "checkedAt": {
                      "type": "string"
                    },
                    "environment": {
                      "type": "string"
                    },
                    "dryRun": {
                      "type": "boolean"
                    },
                    "stats": {
                      "type": "object",
                      "description": "autorizadas24h, rejeitadas24h, canceladas24h, emAndamento, jobsPendentes, webhooksPendentes, emitentesAtivos, tomadores"
                    },
                    "alerts": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "key": {
                            "type": "string"
                          },
                          "severity": {
                            "type": "string",
                            "enum": [
                              "critical",
                              "warning",
                              "info"
                            ]
                          },
                          "title": {
                            "type": "string"
                          },
                          "detail": {
                            "type": "string"
                          },
                          "count": {
                            "type": "integer"
                          },
                          "firstSeenAt": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/health": {
      "get": {
        "summary": "Estado do serviço (público, sem chave)",
        "tags": [
          "Serviço"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "ok",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "env": {
                      "type": "string",
                      "enum": [
                        "restricted",
                        "production"
                      ]
                    },
                    "dryRun": {
                      "type": "boolean"
                    },
                    "productionEnabled": {
                      "type": "boolean"
                    },
                    "verAplic": {
                      "type": "string"
                    },
                    "simulator": {
                      "type": "boolean"
                    },
                    "sefinBaseUrl": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/nfse/simulate": {
      "post": {
        "summary": "Simula ISS, retenções federais e líquido de uma nota (nada é criado nem transmitido)",
        "tags": [
          "NFS-e"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "issuerCode",
                  "grossValue",
                  "customerTaxId"
                ],
                "properties": {
                  "issuerCode": {
                    "type": "string"
                  },
                  "grossValue": {
                    "type": "number"
                  },
                  "customerTaxId": {
                    "type": "string",
                    "description": "CPF ou CNPJ do tomador"
                  },
                  "fiscalOverrides": {
                    "type": "object"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "iss, federais, totalRetido, netValue"
          },
          "404": {
            "description": "emitente não encontrado"
          }
        }
      }
    }
  },
  "x-webhooks": {
    "nfse.status": {
      "post": {
        "summary": "Callback de mudança de status",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookPayload"
              }
            }
          }
        }
      }
    }
  }
}