{
  "openapi": "3.0.3",
  "info": {
    "title": "UseSign — API",
    "version": "1.0.0",
    "description": "Assinatura eletrônica avançada. Domínio em português sem acento, snake_case; protocolo em inglês. Erros seguem a RFC 9457 — ramifique por `codigo`, nunca pelo texto."
  },
  "servers": [
    {
      "url": "/",
      "description": "Este servidor (usado pelo botão de teste do portal)"
    },
    {
      "url": "https://usesign.com.br",
      "description": "Produção"
    }
  ],
  "tags": [
    {
      "name": "Documentos"
    },
    {
      "name": "Interno"
    },
    {
      "name": "Onboarding"
    },
    {
      "name": "Sandbox"
    },
    {
      "name": "Uso"
    },
    {
      "name": "Verificação"
    },
    {
      "name": "Webhooks"
    }
  ],
  "components": {
    "securitySchemes": {
      "chaveDeApi": {
        "type": "http",
        "scheme": "bearer",
        "description": "Chave de API da organização: `Authorization: Bearer evo_sk_live_…`"
      }
    },
    "schemas": {
      "Problema": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Link para a página que explica como resolver."
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer",
            "minimum": -9007199254740991,
            "maximum": 9007199254740991
          },
          "detail": {
            "type": "string"
          },
          "instance": {
            "type": "string"
          },
          "codigo": {
            "type": "string",
            "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
          },
          "requisicao_id": {
            "type": "string",
            "description": "Informe este valor ao suporte."
          },
          "erros": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "campo": {
                  "type": "string"
                },
                "mensagem": {
                  "type": "string"
                }
              },
              "required": [
                "campo",
                "mensagem"
              ],
              "additionalProperties": false
            }
          }
        },
        "required": [
          "type",
          "title",
          "status",
          "detail",
          "instance",
          "codigo",
          "requisicao_id",
          "erros"
        ],
        "additionalProperties": false
      }
    }
  },
  "paths": {
    "/api/interno/saude": {
      "get": {
        "operationId": "saude",
        "summary": "Estado do serviço",
        "tags": [
          "Interno"
        ],
        "responses": {
          "200": {
            "description": "Estado do serviço",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "estado": {
                      "type": "string",
                      "enum": [
                        "ok",
                        "degradado"
                      ]
                    },
                    "banco": {
                      "type": "boolean"
                    },
                    "trilha_protegida": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "estado",
                    "banco",
                    "trilha_protegida"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        },
        "description": "Usada pelo ping externo. Não faz parte da API pública v1."
      }
    },
    "/api/v1/cadastro": {
      "post": {
        "operationId": "cadastrar",
        "summary": "Cria conta, organização, sandbox e as primeiras chaves",
        "tags": [
          "Onboarding"
        ],
        "responses": {
          "201": {
            "description": "Cria conta, organização, sandbox e as primeiras chaves",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "organizacao_id": {
                      "type": "string"
                    },
                    "organizacao_sandbox_id": {
                      "type": "string"
                    },
                    "usuario_id": {
                      "type": "string"
                    },
                    "plano": {
                      "type": "string",
                      "description": "O plano EFETIVO da conta recém-criada. Hoje é sempre `gratuito`."
                    },
                    "plano_pretendido": {
                      "type": "string",
                      "description": "O plano que veio no pedido. Igual a `plano` quando foi `gratuito`; quando foi um plano pago, é o que a interface deve oferecer para contratar em seguida."
                    },
                    "status": {
                      "type": "string",
                      "description": "Estado da assinatura. Hoje é sempre `ativa` — `trial` deixou de ser escrito em 24/08/2026, quando o teste de 14 dias saiu do produto."
                    },
                    "chaves": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "ambiente": {
                            "type": "string",
                            "enum": [
                              "producao",
                              "teste"
                            ]
                          },
                          "organizacao_id": {
                            "type": "string"
                          },
                          "prefixo": {
                            "type": "string"
                          },
                          "chave": {
                            "type": "string",
                            "description": "Devolvida UMA vez. No banco existe só o SHA-256."
                          }
                        },
                        "required": [
                          "ambiente",
                          "organizacao_id",
                          "prefixo",
                          "chave"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "organizacao_id",
                    "organizacao_sandbox_id",
                    "usuario_id",
                    "plano",
                    "plano_pretendido",
                    "status",
                    "chaves"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "422": {
            "description": "Entrada inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        },
        "description": "Rota pública de onboarding. Devolve DUAS chaves — produção e sandbox — e cada uma é mostrada uma única vez: no banco existe só o SHA-256 delas.\n\nO ambiente de teste é uma **organização irmã**, não uma opção da mesma conta: ele tem documentos, ids, webhooks e chave próprios, e a chave de teste não enxerga dados de produção (nem o contrário — um `id` de um ambiente responde 404 no outro).\n\n⚠️ **A sandbox tem cota própria**, do mesmo tamanho do plano. Criar documento nela não desconta da cota de produção, mas pode esgotar a dela e responder 402 — consulte `GET /api/v1/uso` com a chave de teste para ver esse consumo separadamente.\n\nO que os dois ambientes **compartilham** é só o cadastro da empresa: razão social, CNPJ, e-mail de resposta e a assinatura da empresa registrada no painel. A sandbox é o espelho da mesma pessoa jurídica — registrar a assinatura uma vez faz `modo_assinatura: \"organizacao\"` funcionar com as duas chaves.\n\nDocumento gerado em sandbox sai **marcado como teste** e sem valor probatório, e a retenção dos arquivos lá é de **1 mês**. Não guarde nada de valor nela.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "nome_da_organizacao": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 200
                  },
                  "cnpj": {
                    "type": "string",
                    "minLength": 14,
                    "maxLength": 18
                  },
                  "nome": {
                    "type": "string",
                    "minLength": 2,
                    "maxLength": 200
                  },
                  "email": {
                    "type": "string",
                    "maxLength": 320,
                    "format": "email",
                    "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                  },
                  "senha": {
                    "type": "string",
                    "minLength": 12,
                    "maxLength": 200,
                    "description": "Mínimo de 12 caracteres. Guardada com argon2id."
                  },
                  "plano": {
                    "default": "gratuito",
                    "description": "Plano PRETENDIDO. ⚠️ A conta é sempre criada no `gratuito`: plano pago passa a existir só depois da contratação paga, feita pelo titular no painel. O valor enviado aqui é validado (plano inexistente é recusado) e devolvido em `plano_pretendido`, para que a interface leve a pessoa à contratação em seguida. Códigos: `gratuito` (2 documentos/mês, **sem API** — a chave é recusada), `essencial` (25/mês, 1 empresa) ou `profissional` (50/mês, até 5 empresas). A lista viva está em https://usesign.com.br/precos. Nos planos com mais de uma empresa, os documentos do mês são divididos livremente entre elas — a cota é da conta, não de cada CNPJ.",
                    "type": "string",
                    "maxLength": 32
                  }
                },
                "required": [
                  "nome_da_organizacao",
                  "nome",
                  "email",
                  "senha"
                ]
              }
            }
          }
        }
      }
    },
    "/api/v1/documentos": {
      "get": {
        "operationId": "listar_documentos",
        "summary": "Lista documentos da organização",
        "tags": [
          "Documentos"
        ],
        "responses": {
          "200": {
            "description": "Lista documentos da organização",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "dados": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "nome": {
                            "type": "string"
                          },
                          "referencia_externa": {
                            "nullable": true,
                            "type": "string"
                          },
                          "status": {
                            "type": "string"
                          },
                          "modo_ordem": {
                            "type": "string"
                          },
                          "ambiente": {
                            "type": "string"
                          },
                          "hash_original": {
                            "type": "string"
                          },
                          "hash_final": {
                            "nullable": true,
                            "description": "Só depois do selo. É o aceito por /verificar.",
                            "type": "string"
                          },
                          "bytes_original": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "paginas": {
                            "nullable": true,
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "criado_em": {
                            "type": "string"
                          },
                          "expira_em": {
                            "type": "string"
                          },
                          "concluido_em": {
                            "nullable": true,
                            "type": "string"
                          },
                          "cancelado_em": {
                            "nullable": true,
                            "type": "string"
                          },
                          "cancelado_motivo": {
                            "nullable": true,
                            "type": "string"
                          },
                          "retencao_ate": {
                            "type": "string"
                          },
                          "signatarios": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "id": {
                                  "type": "string"
                                },
                                "nome": {
                                  "type": "string"
                                },
                                "documento": {
                                  "type": "string",
                                  "description": "Mascarado."
                                },
                                "papel": {
                                  "type": "string"
                                },
                                "posicao": {
                                  "type": "integer",
                                  "minimum": -9007199254740991,
                                  "maximum": 9007199254740991
                                },
                                "status": {
                                  "type": "string"
                                },
                                "assinado_em": {
                                  "nullable": true,
                                  "type": "string"
                                },
                                "recusado_em": {
                                  "nullable": true,
                                  "type": "string"
                                },
                                "recusa_motivo": {
                                  "nullable": true,
                                  "type": "string"
                                }
                              },
                              "required": [
                                "id",
                                "nome",
                                "documento",
                                "papel",
                                "posicao",
                                "status",
                                "assinado_em",
                                "recusado_em",
                                "recusa_motivo"
                              ],
                              "additionalProperties": false
                            }
                          }
                        },
                        "required": [
                          "id",
                          "nome",
                          "referencia_externa",
                          "status",
                          "modo_ordem",
                          "ambiente",
                          "hash_original",
                          "hash_final",
                          "bytes_original",
                          "paginas",
                          "criado_em",
                          "expira_em",
                          "concluido_em",
                          "cancelado_em",
                          "cancelado_motivo",
                          "retencao_ate",
                          "signatarios"
                        ],
                        "additionalProperties": false
                      }
                    },
                    "proximo_cursor": {
                      "nullable": true,
                      "type": "string"
                    },
                    "tem_mais": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "dados",
                    "proximo_cursor",
                    "tem_mais"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Chave de API inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "422": {
            "description": "Entrada inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        },
        "description": "Paginação por cursor opaco, ordenada por `(criado_em DESC, id DESC)`. Offset está fora de propósito: um documento criado entre a página 1 e a 2 faria o cliente PULAR registros.",
        "parameters": [
          {
            "name": "limite",
            "in": "query",
            "required": false,
            "schema": {
              "default": 25,
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "schema": {
              "description": "Valor de `proximo_cursor` da página anterior.",
              "type": "string"
            },
            "description": "Valor de `proximo_cursor` da página anterior."
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "aguardando",
                "assinado",
                "assinado_parcialmente",
                "recusado",
                "expirado",
                "cancelado"
              ]
            }
          },
          {
            "name": "referencia_externa",
            "in": "query",
            "required": false,
            "schema": {
              "description": "Pode devolver N: `referencia_externa` não é única, de propósito.",
              "type": "string",
              "maxLength": 128
            },
            "description": "Pode devolver N: `referencia_externa` não é única, de propósito."
          },
          {
            "name": "hash_original",
            "in": "query",
            "required": false,
            "schema": {
              "description": "SHA-256 em hex. Busca AUTENTICADA — a rota pública /verificar aceita só hash_final.",
              "type": "string",
              "pattern": "^[0-9a-f]{64}$"
            },
            "description": "SHA-256 em hex. Busca AUTENTICADA — a rota pública /verificar aceita só hash_final."
          }
        ],
        "security": [
          {
            "chaveDeApi": []
          }
        ]
      },
      "post": {
        "operationId": "criar_documento",
        "summary": "Cria um documento e convida os signatários",
        "tags": [
          "Documentos"
        ],
        "responses": {
          "201": {
            "description": "Cria um documento e convida os signatários",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "nome": {
                      "type": "string"
                    },
                    "referencia_externa": {
                      "nullable": true,
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    },
                    "modo_ordem": {
                      "type": "string"
                    },
                    "ambiente": {
                      "type": "string"
                    },
                    "hash_original": {
                      "type": "string",
                      "description": "SHA-256 em hex dos bytes que entraram."
                    },
                    "bytes_original": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "paginas": {
                      "nullable": true,
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "paginas_tamanho": {
                      "description": "Largura e altura de CADA página, em pontos, na ordem. É a régua para posicionar a assinatura na próxima criação sem abrir o PDF. Vem da MediaBox — a mesma caixa em que a montagem desenha.",
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "largura": {
                            "type": "number"
                          },
                          "altura": {
                            "type": "number"
                          }
                        },
                        "required": [
                          "largura",
                          "altura"
                        ],
                        "additionalProperties": false
                      }
                    },
                    "avisos": {
                      "description": "Avisos, NÃO erros: o documento foi criado. `area_com_texto` diz que a assinatura vai por cima de texto do documento — o que é o esperado quando se assina sobre a linha de sublinhados. `pagina_sem_texto_extraivel` diz que NÃO FOI POSSÍVEL verificar (escaneado, imagem, texto vetorizado): ausência de aviso não prova área livre.",
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "codigo": {
                            "type": "string",
                            "enum": [
                              "area_com_texto",
                              "pagina_sem_texto_extraivel"
                            ]
                          },
                          "campo": {
                            "type": "string",
                            "description": "Caminho na entrada, ex. `signatarios.0.campos.1`."
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "codigo",
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    },
                    "criado_em": {
                      "type": "string"
                    },
                    "expira_em": {
                      "type": "string"
                    },
                    "retencao_ate": {
                      "type": "string"
                    },
                    "signatarios": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "nome": {
                            "type": "string"
                          },
                          "documento": {
                            "type": "string",
                            "description": "Mascarado: apenas os dígitos do meio."
                          },
                          "papel": {
                            "type": "string"
                          },
                          "posicao": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "status": {
                            "type": "string"
                          },
                          "url_assinatura": {
                            "nullable": true,
                            "description": "Devolvida UMA VEZ, na criação. Num replay vem SEMPRE `null`: o token só existe como SHA-256 no banco e não é derivável do hash. Quem perdeu a resposta original usa `POST /api/v1/signatarios/{id}/reconvite`, que emite token e OTP novos.",
                            "type": "string"
                          },
                          "token_vivo": {
                            "description": "Só no replay: indica se o link original ainda estaria válido.",
                            "type": "boolean"
                          },
                          "campos": {
                            "description": "Devolvido como confirmação do que foi gravado. Ausente ou vazio quando o signatário assina no bloco de assinatura padrão.",
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "pagina": {
                                  "type": "integer",
                                  "minimum": 1,
                                  "maximum": 9007199254740991,
                                  "description": "1-based: a primeira página é 1."
                                },
                                "x": {
                                  "type": "number",
                                  "minimum": 0,
                                  "description": "Pontos a partir da BORDA ESQUERDA."
                                },
                                "y": {
                                  "type": "number",
                                  "minimum": 0,
                                  "description": "Pontos a partir da borda de BAIXO — origem do PDF."
                                },
                                "largura": {
                                  "type": "number",
                                  "minimum": 0,
                                  "exclusiveMinimum": true,
                                  "maximum": 2000
                                },
                                "altura": {
                                  "type": "number",
                                  "minimum": 0,
                                  "exclusiveMinimum": true,
                                  "maximum": 2000
                                },
                                "area_com_texto": {
                                  "type": "boolean",
                                  "description": "O que a detecção viu quando o campo foi definido: havia texto do documento nesta área. É projeção, não prova — ver `avisos`."
                                }
                              },
                              "required": [
                                "pagina",
                                "x",
                                "y",
                                "largura",
                                "altura",
                                "area_com_texto"
                              ],
                              "additionalProperties": false
                            }
                          }
                        },
                        "required": [
                          "id",
                          "nome",
                          "documento",
                          "papel",
                          "posicao",
                          "status",
                          "url_assinatura"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "id",
                    "nome",
                    "referencia_externa",
                    "status",
                    "modo_ordem",
                    "ambiente",
                    "hash_original",
                    "bytes_original",
                    "paginas",
                    "criado_em",
                    "expira_em",
                    "retencao_ate",
                    "signatarios"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Chave de API inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "402": {
            "description": "Cota do plano excedida · Teto de excedente atingido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "403": {
            "description": "Chave de ambiente errado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "409": {
            "description": "Requisição em andamento · Chave de idempotência reutilizada · Requisição em andamento · Chave de idempotência reutilizada",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "422": {
            "description": "Entrada inválida · CPF inválido · O arquivo não é um PDF · Campo de assinatura fora da página",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        },
        "description": "Aceita `multipart/form-data` (campo `arquivo` + campo `dados` com o JSON) ou JSON puro com `arquivo_base64`. A `url_assinatura` de cada signatário é devolvida UMA vez: ela contém o token, que no banco existe apenas como SHA-256.\n\n### Onde a assinatura entra na página\n\nPor padrão — `campos` ausente — o documento sai com **rubrica em cada página** e um **bloco de assinatura na última**, mais a página de assinaturas e o QR de verificação. Para assinar em cima da linha de um contrato, informe `signatarios[].campos[]`: `pagina` (1-based), `x`, `y`, `largura` e `altura` em **pontos** (1/72 de polegada), com a origem no canto **inferior esquerdo** da página. Vindo de um sistema de tela, `y = altura_da_pagina - y_do_topo - altura`. A régua de cada página vem em `paginas_tamanho` na resposta. Quem define campo **sai do bloco do pé** — com os dois, o documento afirmaria duas vezes que a mesma pessoa assinou. A rubrica por página continua para todos.\n\n### A própria empresa como signatária\n\nUm signatário com `modo_assinatura: \"organizacao\"` é a **sua empresa** assinando o documento que ela mesma emitiu: sem link, sem e-mail e sem código. A assinatura arquivada dela é aplicada automaticamente **assim que todos os demais signatários concluírem** — nunca antes, para o documento não afirmar que a emissora assinou enquanto a outra parte ainda decidia.\n\nAntes de usar, registre a assinatura da empresa no painel, em **Minha conta**; sem ela a criação é recusada com 422. O CNPJ da empresa também precisa estar cadastrado, porque ela entra como signatária e todo signatário tem o dígito verificador conferido.\n\nTrês recusas guardam contra documento que ficaria aberto para sempre: **só** a organização na lista (ninguém praticaria o ato que dispara a assinatura dela), e, em `modo_ordem: \"sequencial\"`, a organização fora da última posição (ela não tem link para abrir e travaria a fila). Se a última pessoa **recusar**, a empresa assina mesmo assim caso alguém já tenha assinado — e o documento fecha como `assinado_parcialmente`; se ninguém assinou, ela não assina e o documento fecha como `recusado`.\n\nNa página de assinaturas, cada ato é **descrito** pelo que o sustentou: *\"Código de uso único validado em…\"* para as partes externas, *\"Assinatura da organização, autorizada na emissão em…\"* para a sua empresa. A trilha registra os dois com o mesmo evento `assinatura_registrada`, na mesma cadeia de hash.\n\n### Cota\n\nCada documento criado consome uma unidade da cota do mês, **na criação** — documento cancelado ou expirado continua contando; só não conta quando a própria criação falha. A contagem zera na virada do mês e o que não foi usado **não acumula**.\n\n⚠️ **A cota é da conta, não da empresa.** Se a sua conta tem mais de uma empresa (CNPJ), todas dividem os documentos do plano sem limite individual — o gasto de uma reduz o que sobra para as outras. Consulte `GET /api/v1/uso` e use `conta.documentos_restantes`: `atual` traz apenas o consumo da empresa desta chave, e decidir por ele leva a 402 inesperado. Estourando a cota, o plano ou cobra excedente (até o teto) ou responde 402 `cota_do_plano_excedida`.\n\n### O que a verificação de área NÃO enxerga\n\nA plataforma confere se há texto do documento na área pedida e devolve isso em `avisos` — **avisa, não recusa**, porque assinar sobre a linha de sublinhados é o caso certo. Este exame tem limites conhecidos: ele lê **texto**, e portanto **não vê** linha ou traço desenhado como caminho vetorial (o `______` da linha de assinatura em geral é isto), **não vê** imagem nem página escaneada, e **não vê** texto de anotação. **Ausência de aviso não prova que a área está livre** — prova que não foi encontrado texto. Quando a página não tem texto extraível nenhum, isso vem dito em `pagina_sem_texto_extraivel`. Área que não cabe na página é recusada com 422 `campo_fora_da_pagina`, em vez de corrigida por conta própria.\n\n### Como o convite chega até quem assina\n\nA plataforma envia o convite por **e-mail**, e a mensagem já se apresenta em nome da sua empresa: o remetente aparece como **`Sua Empresa via UseSign`**, o assunto é *\"Sua Empresa enviou um documento para você assinar: contrato.pdf\"*, e o corpo explica que o UseSign é a plataforma que a sua empresa usa para coletar assinaturas. O nome vem do cadastro da sua organização.\n\n⚠️ **O endereço de envio continua sendo o da UseSign.** Enviar a partir do seu domínio exigiria SPF, DKIM e DMARC configurados no DNS dele; sem isso o provedor do destinatário trata a mensagem como falsificação e ela vai para spam — o oposto do que se quer. Envio por domínio próprio não está disponível.\n\n**Você também pode entregar o link por conta própria.** A `url_assinatura` devolvida aqui é um link comum: mande por e-mail seu, WhatsApp, SMS ou pelo seu próprio aplicativo. Não é preciso desligar nada — mas lembre que o **código de verificação continua indo por e-mail**, então o signatário ainda precisa de um e-mail válido para concluir a assinatura.\n\n**Perdeu o link?** Ele não é recuperável — no banco o token existe só como SHA-256. Use `POST /api/v1/signatarios/{id}/reconvite`, que emite link e código novos, invalida o anterior e **não consome cota**.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "nome": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 250
                  },
                  "referencia_externa": {
                    "type": "string",
                    "maxLength": 128
                  },
                  "modo_ordem": {
                    "default": "paralela",
                    "type": "string",
                    "enum": [
                      "paralela",
                      "sequencial"
                    ]
                  },
                  "arquivo_base64": {
                    "description": "Alternativa ao multipart. Ignorado quando o arquivo vem no multipart.",
                    "type": "string"
                  },
                  "signatarios": {
                    "minItems": 1,
                    "maxItems": 20,
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "nome": {
                          "type": "string",
                          "minLength": 2,
                          "maxLength": 200
                        },
                        "documento": {
                          "type": "string",
                          "minLength": 11,
                          "maxLength": 18,
                          "description": "CPF ou CNPJ, com ou sem máscara. O dígito verificador é conferido."
                        },
                        "email": {
                          "type": "string",
                          "maxLength": 320,
                          "format": "email",
                          "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                        },
                        "celular": {
                          "description": "E.164 sem o `+`, só dígitos.",
                          "type": "string",
                          "pattern": "^\\d{10,15}$"
                        },
                        "papel": {
                          "type": "string",
                          "enum": [
                            "contratante",
                            "contratada",
                            "testemunha",
                            "interveniente"
                          ]
                        },
                        "canal_otp": {
                          "default": "email",
                          "description": "Hoje apenas `email` é aceito. `sms` e `whatsapp` constam no enum porque o modelo de dados os prevê, mas a criação os RECUSA com 422 — não há canal de entrega implementado, e aceitar em silêncio deixaria o signatário sem receber o código.",
                          "type": "string",
                          "enum": [
                            "email",
                            "sms",
                            "whatsapp"
                          ]
                        },
                        "modo_assinatura": {
                          "description": "`codigo` (padrão) — a pessoa recebe link e valida um código de uso único. `organizacao` — é a PRÓPRIA empresa emissora assinando: sem link e sem código, a assinatura arquivada dela é aplicada automaticamente quando todos os demais concluírem. Exige que a empresa tenha registrado a assinatura no painel (Minha conta), e dispensa `email` para esse signatário. A página de assinaturas descreve o que sustentou cada ato: código validado para a parte externa, autorização na emissão para a organização.",
                          "type": "string",
                          "enum": [
                            "codigo",
                            "organizacao"
                          ]
                        },
                        "campos": {
                          "description": "Onde a assinatura desta pessoa entra na página. OMITIR é o padrão e mantém o comportamento de sempre: rubrica em cada página e bloco de assinatura na última. Quem define campo SAI do bloco do pé — o documento afirmaria duas vezes que a mesma pessoa assinou. A rubrica por página continua para todos.",
                          "maxItems": 20,
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "pagina": {
                                "type": "integer",
                                "minimum": 1,
                                "maximum": 9007199254740991,
                                "description": "1-based: a primeira página é 1."
                              },
                              "x": {
                                "type": "number",
                                "minimum": 0,
                                "description": "Pontos a partir da BORDA ESQUERDA."
                              },
                              "y": {
                                "type": "number",
                                "minimum": 0,
                                "description": "Pontos a partir da borda de BAIXO — origem do PDF."
                              },
                              "largura": {
                                "type": "number",
                                "minimum": 0,
                                "exclusiveMinimum": true,
                                "maximum": 2000
                              },
                              "altura": {
                                "type": "number",
                                "minimum": 0,
                                "exclusiveMinimum": true,
                                "maximum": 2000
                              }
                            },
                            "required": [
                              "pagina",
                              "x",
                              "y",
                              "largura",
                              "altura"
                            ]
                          }
                        }
                      },
                      "required": [
                        "nome",
                        "documento",
                        "papel"
                      ]
                    }
                  },
                  "lembretes": {
                    "description": "Manda lembrete a quem não assinar (D+2, D+5 e véspera). Ausente = o padrão da empresa.",
                    "type": "boolean"
                  },
                  "dias_para_assinar": {
                    "description": "Por quantos dias o link de assinatura vale, contados da criação. Ausente = 14, que é o padrão E o máximo: prazo maior significa link de assinatura vivo por mais tempo, e cada dia a mais é mais janela para ele vazar ou ser encaminhado. Depois do prazo o documento fica `expirado` e o link deixa de abrir.",
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 14
                  }
                },
                "required": [
                  "nome",
                  "signatarios"
                ]
              },
              "examples": {
                "padrao": {
                  "summary": "Sem posição — rubrica por página e bloco de assinatura na última",
                  "value": {
                    "nome": "Contrato de prestação de serviços",
                    "referencia_externa": "OS-4711",
                    "arquivo_base64": "<PDF em base64>",
                    "signatarios": [
                      {
                        "nome": "Maria de Souza",
                        "documento": "11144477735",
                        "email": "maria@exemplo.com",
                        "papel": "contratante"
                      }
                    ]
                  }
                },
                "com_posicao": {
                  "summary": "Assinatura NA LINHA do contrato — pontos PDF, origem no canto inferior esquerdo",
                  "value": {
                    "nome": "Contrato de prestação de serviços",
                    "arquivo_base64": "<PDF em base64>",
                    "dias_para_assinar": 7,
                    "signatarios": [
                      {
                        "nome": "Maria de Souza",
                        "documento": "11144477735",
                        "email": "maria@exemplo.com",
                        "papel": "contratante",
                        "campos": [
                          {
                            "pagina": 5,
                            "x": 90,
                            "y": 180,
                            "largura": 200,
                            "altura": 45
                          }
                        ]
                      },
                      {
                        "nome": "Construtora Exemplo LTDA",
                        "documento": "11222333000181",
                        "email": "contratos@exemplo.com",
                        "papel": "contratada",
                        "campos": [
                          {
                            "pagina": 5,
                            "x": 330,
                            "y": 180,
                            "largura": 200,
                            "altura": 45
                          }
                        ]
                      }
                    ]
                  }
                },
                "com_a_empresa": {
                  "summary": "A sua empresa também assina — sem link, sem e-mail e sem código",
                  "value": {
                    "nome": "Contrato de prestação de serviços",
                    "referencia_externa": "OS-4711",
                    "arquivo_base64": "<PDF em base64>",
                    "signatarios": [
                      {
                        "nome": "Maria de Souza",
                        "documento": "11144477735",
                        "email": "maria@exemplo.com",
                        "papel": "contratante"
                      },
                      {
                        "nome": "Sua Empresa LTDA",
                        "documento": "11222333000181",
                        "papel": "contratada",
                        "modo_assinatura": "organizacao"
                      }
                    ]
                  }
                }
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "arquivo": {
                    "type": "string",
                    "format": "binary",
                    "description": "O PDF, em bytes. Dispensa `arquivo_base64`."
                  },
                  "dados": {
                    "type": "object",
                    "properties": {
                      "nome": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 250
                      },
                      "referencia_externa": {
                        "type": "string",
                        "maxLength": 128
                      },
                      "modo_ordem": {
                        "default": "paralela",
                        "type": "string",
                        "enum": [
                          "paralela",
                          "sequencial"
                        ]
                      },
                      "arquivo_base64": {
                        "description": "Alternativa ao multipart. Ignorado quando o arquivo vem no multipart.",
                        "type": "string"
                      },
                      "signatarios": {
                        "minItems": 1,
                        "maxItems": 20,
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "nome": {
                              "type": "string",
                              "minLength": 2,
                              "maxLength": 200
                            },
                            "documento": {
                              "type": "string",
                              "minLength": 11,
                              "maxLength": 18,
                              "description": "CPF ou CNPJ, com ou sem máscara. O dígito verificador é conferido."
                            },
                            "email": {
                              "type": "string",
                              "maxLength": 320,
                              "format": "email",
                              "pattern": "^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"
                            },
                            "celular": {
                              "description": "E.164 sem o `+`, só dígitos.",
                              "type": "string",
                              "pattern": "^\\d{10,15}$"
                            },
                            "papel": {
                              "type": "string",
                              "enum": [
                                "contratante",
                                "contratada",
                                "testemunha",
                                "interveniente"
                              ]
                            },
                            "canal_otp": {
                              "default": "email",
                              "description": "Hoje apenas `email` é aceito. `sms` e `whatsapp` constam no enum porque o modelo de dados os prevê, mas a criação os RECUSA com 422 — não há canal de entrega implementado, e aceitar em silêncio deixaria o signatário sem receber o código.",
                              "type": "string",
                              "enum": [
                                "email",
                                "sms",
                                "whatsapp"
                              ]
                            },
                            "modo_assinatura": {
                              "description": "`codigo` (padrão) — a pessoa recebe link e valida um código de uso único. `organizacao` — é a PRÓPRIA empresa emissora assinando: sem link e sem código, a assinatura arquivada dela é aplicada automaticamente quando todos os demais concluírem. Exige que a empresa tenha registrado a assinatura no painel (Minha conta), e dispensa `email` para esse signatário. A página de assinaturas descreve o que sustentou cada ato: código validado para a parte externa, autorização na emissão para a organização.",
                              "type": "string",
                              "enum": [
                                "codigo",
                                "organizacao"
                              ]
                            },
                            "campos": {
                              "description": "Onde a assinatura desta pessoa entra na página. OMITIR é o padrão e mantém o comportamento de sempre: rubrica em cada página e bloco de assinatura na última. Quem define campo SAI do bloco do pé — o documento afirmaria duas vezes que a mesma pessoa assinou. A rubrica por página continua para todos.",
                              "maxItems": 20,
                              "type": "array",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "pagina": {
                                    "type": "integer",
                                    "minimum": 1,
                                    "maximum": 9007199254740991,
                                    "description": "1-based: a primeira página é 1."
                                  },
                                  "x": {
                                    "type": "number",
                                    "minimum": 0,
                                    "description": "Pontos a partir da BORDA ESQUERDA."
                                  },
                                  "y": {
                                    "type": "number",
                                    "minimum": 0,
                                    "description": "Pontos a partir da borda de BAIXO — origem do PDF."
                                  },
                                  "largura": {
                                    "type": "number",
                                    "minimum": 0,
                                    "exclusiveMinimum": true,
                                    "maximum": 2000
                                  },
                                  "altura": {
                                    "type": "number",
                                    "minimum": 0,
                                    "exclusiveMinimum": true,
                                    "maximum": 2000
                                  }
                                },
                                "required": [
                                  "pagina",
                                  "x",
                                  "y",
                                  "largura",
                                  "altura"
                                ]
                              }
                            }
                          },
                          "required": [
                            "nome",
                            "documento",
                            "papel"
                          ]
                        }
                      },
                      "lembretes": {
                        "description": "Manda lembrete a quem não assinar (D+2, D+5 e véspera). Ausente = o padrão da empresa.",
                        "type": "boolean"
                      },
                      "dias_para_assinar": {
                        "description": "Por quantos dias o link de assinatura vale, contados da criação. Ausente = 14, que é o padrão E o máximo: prazo maior significa link de assinatura vivo por mais tempo, e cada dia a mais é mais janela para ele vazar ou ser encaminhado. Depois do prazo o documento fica `expirado` e o link deixa de abrir.",
                        "type": "integer",
                        "minimum": 1,
                        "maximum": 14
                      }
                    },
                    "required": [
                      "nome",
                      "signatarios"
                    ],
                    "description": "O mesmo corpo JSON, como campo de texto do formulário."
                  }
                },
                "required": [
                  "arquivo",
                  "dados"
                ]
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            },
            "description": "Obrigatória. ⚠️ Derivar a chave da referência externa é ótimo contra retentativa de rede e péssimo quando você quer reenviar o mesmo contrato de propósito: você recebe a resposta antiga. Para criar de novo, use um UUID v4 novo."
          }
        ],
        "security": [
          {
            "chaveDeApi": []
          }
        ]
      }
    },
    "/api/v1/documentos/{id}": {
      "get": {
        "operationId": "consultar_documento",
        "summary": "Consulta um documento",
        "tags": [
          "Documentos"
        ],
        "responses": {
          "200": {
            "description": "Consulta um documento",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "nome": {
                      "type": "string"
                    },
                    "referencia_externa": {
                      "nullable": true,
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    },
                    "modo_ordem": {
                      "type": "string"
                    },
                    "ambiente": {
                      "type": "string"
                    },
                    "hash_original": {
                      "type": "string"
                    },
                    "hash_final": {
                      "nullable": true,
                      "description": "Só depois do selo. É o aceito por /verificar.",
                      "type": "string"
                    },
                    "bytes_original": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "paginas": {
                      "nullable": true,
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "criado_em": {
                      "type": "string"
                    },
                    "expira_em": {
                      "type": "string"
                    },
                    "concluido_em": {
                      "nullable": true,
                      "type": "string"
                    },
                    "cancelado_em": {
                      "nullable": true,
                      "type": "string"
                    },
                    "cancelado_motivo": {
                      "nullable": true,
                      "type": "string"
                    },
                    "retencao_ate": {
                      "type": "string"
                    },
                    "signatarios": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "nome": {
                            "type": "string"
                          },
                          "documento": {
                            "type": "string",
                            "description": "Mascarado."
                          },
                          "papel": {
                            "type": "string"
                          },
                          "posicao": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "status": {
                            "type": "string"
                          },
                          "assinado_em": {
                            "nullable": true,
                            "type": "string"
                          },
                          "recusado_em": {
                            "nullable": true,
                            "type": "string"
                          },
                          "recusa_motivo": {
                            "nullable": true,
                            "type": "string"
                          }
                        },
                        "required": [
                          "id",
                          "nome",
                          "documento",
                          "papel",
                          "posicao",
                          "status",
                          "assinado_em",
                          "recusado_em",
                          "recusa_motivo"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "id",
                    "nome",
                    "referencia_externa",
                    "status",
                    "modo_ordem",
                    "ambiente",
                    "hash_original",
                    "hash_final",
                    "bytes_original",
                    "paginas",
                    "criado_em",
                    "expira_em",
                    "concluido_em",
                    "cancelado_em",
                    "cancelado_motivo",
                    "retencao_ate",
                    "signatarios"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Chave de API inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "404": {
            "description": "Documento não encontrado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            }
          }
        ],
        "security": [
          {
            "chaveDeApi": []
          }
        ]
      }
    },
    "/api/v1/documentos/{id}/arquivo": {
      "get": {
        "operationId": "baixar_arquivo_montado",
        "summary": "Baixa o documento montado",
        "tags": [
          "Documentos"
        ],
        "responses": {
          "200": {
            "description": "Baixa o documento montado",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {},
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Chave de API inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "404": {
            "description": "Documento não encontrado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        },
        "description": "Devolve `application/pdf` do documento montado pela plataforma: o original com rubrica em cada página, a página de assinaturas com as evidências e o QR de verificação. Disponível somente depois de o documento ser concluído e montado — até lá, 404. Não contém assinatura criptográfica PAdES.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            }
          }
        ],
        "security": [
          {
            "chaveDeApi": []
          }
        ]
      }
    },
    "/api/v1/documentos/{id}/arquivo-original": {
      "get": {
        "operationId": "baixar_arquivo_original",
        "summary": "Baixa o PDF original",
        "tags": [
          "Documentos"
        ],
        "responses": {
          "200": {
            "description": "Baixa o PDF original",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {},
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Chave de API inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "404": {
            "description": "Documento não encontrado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        },
        "description": "Devolve `application/pdf` direto. O conteúdo é conferido contra o hash gravado.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            }
          }
        ],
        "security": [
          {
            "chaveDeApi": []
          }
        ]
      }
    },
    "/api/v1/documentos/{id}/cancelamento": {
      "post": {
        "operationId": "cancelar_documento",
        "summary": "Cancela um documento em andamento",
        "tags": [
          "Documentos"
        ],
        "responses": {
          "200": {
            "description": "Cancela um documento em andamento",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "nome": {
                      "type": "string"
                    },
                    "referencia_externa": {
                      "nullable": true,
                      "type": "string"
                    },
                    "status": {
                      "type": "string"
                    },
                    "modo_ordem": {
                      "type": "string"
                    },
                    "ambiente": {
                      "type": "string"
                    },
                    "hash_original": {
                      "type": "string"
                    },
                    "hash_final": {
                      "nullable": true,
                      "description": "Só depois do selo. É o aceito por /verificar.",
                      "type": "string"
                    },
                    "bytes_original": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "paginas": {
                      "nullable": true,
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "criado_em": {
                      "type": "string"
                    },
                    "expira_em": {
                      "type": "string"
                    },
                    "concluido_em": {
                      "nullable": true,
                      "type": "string"
                    },
                    "cancelado_em": {
                      "nullable": true,
                      "type": "string"
                    },
                    "cancelado_motivo": {
                      "nullable": true,
                      "type": "string"
                    },
                    "retencao_ate": {
                      "type": "string"
                    },
                    "signatarios": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "nome": {
                            "type": "string"
                          },
                          "documento": {
                            "type": "string",
                            "description": "Mascarado."
                          },
                          "papel": {
                            "type": "string"
                          },
                          "posicao": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "status": {
                            "type": "string"
                          },
                          "assinado_em": {
                            "nullable": true,
                            "type": "string"
                          },
                          "recusado_em": {
                            "nullable": true,
                            "type": "string"
                          },
                          "recusa_motivo": {
                            "nullable": true,
                            "type": "string"
                          }
                        },
                        "required": [
                          "id",
                          "nome",
                          "documento",
                          "papel",
                          "posicao",
                          "status",
                          "assinado_em",
                          "recusado_em",
                          "recusa_motivo"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "id",
                    "nome",
                    "referencia_externa",
                    "status",
                    "modo_ordem",
                    "ambiente",
                    "hash_original",
                    "hash_final",
                    "bytes_original",
                    "paginas",
                    "criado_em",
                    "expira_em",
                    "concluido_em",
                    "cancelado_em",
                    "cancelado_motivo",
                    "retencao_ate",
                    "signatarios"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Chave de API inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "404": {
            "description": "Documento não encontrado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "409": {
            "description": "Documento já concluído · Requisição em andamento · Chave de idempotência reutilizada",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "422": {
            "description": "Entrada inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        },
        "description": "Cancelar não apaga: o documento, a trilha e a verificação pública continuam existindo. Os links dos signatários são invalidados no mesmo ato.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "motivo": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 500
                  }
                },
                "required": [
                  "motivo"
                ]
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            },
            "description": "Obrigatória. ⚠️ Derivar a chave da referência externa é ótimo contra retentativa de rede e péssimo quando você quer reenviar o mesmo contrato de propósito: você recebe a resposta antiga. Para criar de novo, use um UUID v4 novo."
          }
        ],
        "security": [
          {
            "chaveDeApi": []
          }
        ]
      }
    },
    "/api/v1/signatarios/{id}/reconvite": {
      "post": {
        "operationId": "reconvidar_signatario",
        "summary": "Reenvia o convite de um signatário, com link e código novos",
        "tags": [
          "Documentos"
        ],
        "responses": {
          "200": {
            "description": "Reenvia o convite de um signatário, com link e código novos",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "signatario_id": {
                      "type": "string"
                    },
                    "documento_id": {
                      "type": "string"
                    },
                    "url_assinatura": {
                      "type": "string",
                      "description": "Devolvida UMA VEZ. O link anterior desta pessoa deixou de valer neste momento."
                    },
                    "expira_em": {
                      "type": "string",
                      "description": "O prazo do DOCUMENTO, que o reconvite não estende."
                    },
                    "email_enfileirado": {
                      "type": "boolean",
                      "description": "O e-mail entrou na fila de envio. `false` não invalida o link acima."
                    }
                  },
                  "required": [
                    "signatario_id",
                    "documento_id",
                    "url_assinatura",
                    "expira_em",
                    "email_enfileirado"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Chave de API inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "403": {
            "description": "Chave de ambiente errado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "404": {
            "description": "Documento não encontrado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "409": {
            "description": "Documento já concluído · Requisição em andamento · Chave de idempotência reutilizada",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "422": {
            "description": "Entrada inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        },
        "description": "Emite um link de assinatura NOVO para quem ainda não assinou, e **invalida o anterior no mesmo ato** — o token de link é de uso único por signatário. Use quando a pessoa apagou o e-mail, não recebeu, ou o link expirou.\n\n**Não consome cota**: nenhum documento novo é criado. O documento, a trilha e o hash original são os mesmos; o reconvite entra como um evento a mais (`reconvite_enviado`), sem reescrever nada.\n\nSó vale para quem está `aguardando`. Quem já assinou ou recusou tem ato registrado na trilha, e reabrir o link dele reabriria um ato concluído. Em documento sequencial, quem ainda não é a vez consta como `aguardando_vez` e também é recusado.\n\nA `url_assinatura` é devolvida **uma única vez**, aqui: no banco o token só existe como SHA-256. O e-mail também é enfileirado — `email_enfileirado: false` significa que a fila falhou, mas o link da resposta continua válido.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {}
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
              "description": "O `id` do signatário, devolvido na criação."
            },
            "description": "O `id` do signatário, devolvido na criação."
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            },
            "description": "Obrigatória. ⚠️ Derivar a chave da referência externa é ótimo contra retentativa de rede e péssimo quando você quer reenviar o mesmo contrato de propósito: você recebe a resposta antiga. Para criar de novo, use um UUID v4 novo."
          }
        ],
        "security": [
          {
            "chaveDeApi": []
          }
        ]
      }
    },
    "/api/v1/teste/documentos/{id}/assinar": {
      "post": {
        "operationId": "teste_assinar",
        "summary": "Simula o ato completo do signatário (sandbox)",
        "tags": [
          "Sandbox"
        ],
        "responses": {
          "200": {
            "description": "Simula o ato completo do signatário (sandbox)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "documento_id": {
                      "type": "string"
                    },
                    "signatario_id": {
                      "type": "string"
                    },
                    "status_do_signatario": {
                      "type": "string"
                    },
                    "status_do_documento": {
                      "type": "string"
                    },
                    "assinado_em": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "documento_id",
                    "signatario_id",
                    "status_do_signatario",
                    "status_do_documento",
                    "assinado_em"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Chave de API inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "403": {
            "description": "Chave de ambiente errado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "404": {
            "description": "Documento não encontrado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "409": {
            "description": "Documento já concluído · Requisição em andamento · Chave de idempotência reutilizada",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "410": {
            "description": "Código expirado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "422": {
            "description": "Entrada inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "429": {
            "description": "Tentativas de código esgotadas · Limite de requisições excedido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        },
        "description": "Valida o OTP e grava a assinatura pelo MESMO caminho do fluxo real. Só existe em `ambiente=teste`; em produção responde 404.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "signatario_id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "codigo": {
                    "type": "string",
                    "pattern": "^\\d{6}$"
                  }
                },
                "required": [
                  "signatario_id",
                  "codigo"
                ]
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            },
            "description": "Obrigatória. ⚠️ Derivar a chave da referência externa é ótimo contra retentativa de rede e péssimo quando você quer reenviar o mesmo contrato de propósito: você recebe a resposta antiga. Para criar de novo, use um UUID v4 novo."
          }
        ],
        "security": [
          {
            "chaveDeApi": []
          }
        ]
      }
    },
    "/api/v1/teste/otps": {
      "get": {
        "operationId": "teste_emitir_otp_get",
        "summary": "Emite e devolve um código OTP em claro (sandbox) — obsoleto",
        "tags": [
          "Sandbox"
        ],
        "responses": {
          "200": {
            "description": "Emite e devolve um código OTP em claro (sandbox) — obsoleto",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "signatario_id": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Em claro. Só existe em ambiente de teste."
                    },
                    "canal": {
                      "type": "string"
                    },
                    "destino_mascarado": {
                      "type": "string"
                    },
                    "expira_em": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "signatario_id",
                    "codigo",
                    "canal",
                    "destino_mascarado",
                    "expira_em"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Chave de API inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "403": {
            "description": "Chave de ambiente errado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "404": {
            "description": "Documento não encontrado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "410": {
            "description": "Convite esgotado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        },
        "description": "Só existe em `ambiente=teste`. Em produção responde 404.\n\n⚠️ **Obsoleto — use `POST /api/v1/teste/otps`.** Emitir um código cria um recurso e invalida o anterior, o que não é o que um `GET` deve fazer: um retry automático do seu cliente HTTP derruba o código que você acabou de receber. O comportamento dos dois é idêntico; só o método muda.",
        "parameters": [
          {
            "name": "signatario_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            }
          }
        ],
        "security": [
          {
            "chaveDeApi": []
          }
        ]
      },
      "post": {
        "operationId": "teste_emitir_otp",
        "summary": "Emite e devolve um código OTP em claro (sandbox)",
        "tags": [
          "Sandbox"
        ],
        "responses": {
          "200": {
            "description": "Emite e devolve um código OTP em claro (sandbox)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "signatario_id": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Em claro. Só existe em ambiente de teste."
                    },
                    "canal": {
                      "type": "string"
                    },
                    "destino_mascarado": {
                      "type": "string"
                    },
                    "expira_em": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "signatario_id",
                    "codigo",
                    "canal",
                    "destino_mascarado",
                    "expira_em"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Chave de API inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "403": {
            "description": "Chave de ambiente errado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "404": {
            "description": "Documento não encontrado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "410": {
            "description": "Convite esgotado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        },
        "description": "Só existe em `ambiente=teste`. Em produção responde 404.\n\nEmite um código novo, **invalidando o anterior** — é o mesmo caminho do fluxo real, sem o e-mail: conta contra o teto de 10 emissões do convite e grava `otp_emitido` na trilha.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "signatario_id": {
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  }
                },
                "required": [
                  "signatario_id"
                ]
              }
            }
          }
        },
        "security": [
          {
            "chaveDeApi": []
          }
        ]
      }
    },
    "/api/v1/teste/webhooks/{id}/disparar": {
      "post": {
        "operationId": "teste_disparar_webhook",
        "summary": "Dispara um evento de teste para o endpoint (sandbox)",
        "tags": [
          "Sandbox"
        ],
        "responses": {
          "200": {
            "description": "Dispara um evento de teste para o endpoint (sandbox)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "entrega_id": {
                      "type": "string"
                    },
                    "entregue": {
                      "type": "boolean"
                    },
                    "status_http": {
                      "nullable": true,
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "erro": {
                      "nullable": true,
                      "description": "Código nosso, nunca a resposta do seu servidor.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "entrega_id",
                    "entregue",
                    "status_http",
                    "erro"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Chave de API inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "403": {
            "description": "Chave de ambiente errado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "404": {
            "description": "Documento não encontrado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "409": {
            "description": "Requisição em andamento · Chave de idempotência reutilizada",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "422": {
            "description": "Entrada inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        },
        "description": "Só existe em `ambiente=teste`; em produção responde 404.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "evento": {
                    "default": "documento.assinado",
                    "type": "string",
                    "enum": [
                      "documento.assinado",
                      "documento.assinado_parcialmente",
                      "documento.recusado",
                      "documento.expirado",
                      "documento.cancelado",
                      "signatario.assinou",
                      "signatario.recusou"
                    ]
                  },
                  "documento_id": {
                    "description": "Se omitido, usa um identificador de exemplo.",
                    "type": "string",
                    "format": "uuid",
                    "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
                  },
                  "referencia_externa": {
                    "type": "string",
                    "maxLength": 128
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            },
            "description": "Obrigatória. ⚠️ Derivar a chave da referência externa é ótimo contra retentativa de rede e péssimo quando você quer reenviar o mesmo contrato de propósito: você recebe a resposta antiga. Para criar de novo, use um UUID v4 novo."
          }
        ],
        "security": [
          {
            "chaveDeApi": []
          }
        ]
      }
    },
    "/api/v1/uso": {
      "get": {
        "operationId": "consultar_uso",
        "summary": "Consumo da competência atual e histórico",
        "tags": [
          "Uso"
        ],
        "responses": {
          "200": {
            "description": "Consumo da competência atual e histórico",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ambiente": {
                      "type": "string",
                      "enum": [
                        "producao",
                        "teste"
                      ]
                    },
                    "atual": {
                      "nullable": true,
                      "description": "Consumo desta EMPRESA na competência atual.",
                      "type": "object",
                      "properties": {
                        "competencia": {
                          "type": "string",
                          "description": "AAAA-MM"
                        },
                        "documentos_criados": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "documentos_excedentes": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "sms_enviados": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "whatsapp_enviados": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "carimbos_emitidos": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "excedente_devido_centavos": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Em centavos. R$ 1,90 é 190 — nunca ponto flutuante para dinheiro."
                        },
                        "fechado": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "competencia",
                        "documentos_criados",
                        "documentos_excedentes",
                        "sms_enviados",
                        "whatsapp_enviados",
                        "carimbos_emitidos",
                        "excedente_devido_centavos",
                        "fechado"
                      ],
                      "additionalProperties": false
                    },
                    "conta": {
                      "type": "object",
                      "properties": {
                        "documentos_criados": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Somado entre TODAS as empresas da conta, na competência atual."
                        },
                        "excedente_devido_centavos": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Em centavos, somado entre as empresas da conta."
                        },
                        "documentos_restantes": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Quantos documentos ainda cabem na cota antes de estourar. Zero significa que o próximo documento é excedente (ou 402, se o plano bloqueia)."
                        }
                      },
                      "required": [
                        "documentos_criados",
                        "excedente_devido_centavos",
                        "documentos_restantes"
                      ],
                      "additionalProperties": false,
                      "description": "Consumo da CONTA — a soma de todas as empresas dela. É este número que a cota do plano compara: os documentos do plano são divididos livremente entre as empresas, sem limite individual. Numa conta de uma empresa só, é igual a `atual`."
                    },
                    "limite_do_plano": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991,
                      "description": "Documentos por mês incluídos no plano, já com eventuais ajustes do contrato. Zero quando a organização não tem assinatura ativa — e aí nenhuma criação passa."
                    },
                    "historico": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "competencia": {
                            "type": "string",
                            "description": "AAAA-MM"
                          },
                          "documentos_criados": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "documentos_excedentes": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "sms_enviados": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "whatsapp_enviados": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "carimbos_emitidos": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "excedente_devido_centavos": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991,
                            "description": "Em centavos. R$ 1,90 é 190 — nunca ponto flutuante para dinheiro."
                          },
                          "fechado": {
                            "type": "boolean"
                          }
                        },
                        "required": [
                          "competencia",
                          "documentos_criados",
                          "documentos_excedentes",
                          "sms_enviados",
                          "whatsapp_enviados",
                          "carimbos_emitidos",
                          "excedente_devido_centavos",
                          "fechado"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "ambiente",
                    "atual",
                    "conta",
                    "limite_do_plano",
                    "historico"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Chave de API inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        },
        "description": "Todos os valores monetários são inteiros em centavos. A competência é o mês de referência da cobrança, no fuso da organização.\n\n**A cota é da conta, não da empresa.** Uma conta pode ter várias empresas (CNPJs), com documentos e chaves isolados entre si, e todas dividem os documentos do plano sem limite individual. Para saber quanto ainda cabe, use `conta.documentos_restantes` — `atual` traz apenas o consumo da empresa desta chave.\n\nA contagem **zera na virada do mês** e o que não foi usado não acumula.",
        "parameters": [
          {
            "name": "meses",
            "in": "query",
            "required": false,
            "schema": {
              "default": 6,
              "description": "Quantas competências trazer no histórico (1 a 24).",
              "type": "integer",
              "minimum": 1,
              "maximum": 24
            },
            "description": "Quantas competências trazer no histórico (1 a 24)."
          }
        ],
        "security": [
          {
            "chaveDeApi": []
          }
        ]
      }
    },
    "/api/v1/webhooks": {
      "get": {
        "operationId": "listar_webhooks",
        "summary": "Lista os endpoints de webhook",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Lista os endpoints de webhook",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "dados": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "url": {
                            "type": "string"
                          },
                          "descricao": {
                            "nullable": true,
                            "type": "string"
                          },
                          "eventos": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "ativo": {
                            "type": "boolean"
                          },
                          "falhas_seguidas": {
                            "type": "integer",
                            "minimum": -9007199254740991,
                            "maximum": 9007199254740991
                          },
                          "criado_em": {
                            "type": "string"
                          },
                          "desativado_em": {
                            "nullable": true,
                            "type": "string"
                          },
                          "desativado_motivo": {
                            "nullable": true,
                            "type": "string"
                          }
                        },
                        "required": [
                          "id",
                          "url",
                          "descricao",
                          "eventos",
                          "ativo",
                          "falhas_seguidas",
                          "criado_em",
                          "desativado_em",
                          "desativado_motivo"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "dados"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Chave de API inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        },
        "security": [
          {
            "chaveDeApi": []
          }
        ]
      },
      "post": {
        "operationId": "criar_webhook",
        "summary": "Cadastra um endpoint de webhook",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "201": {
            "description": "Cadastra um endpoint de webhook",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "url": {
                      "type": "string"
                    },
                    "descricao": {
                      "nullable": true,
                      "type": "string"
                    },
                    "eventos": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "ativo": {
                      "type": "boolean"
                    },
                    "falhas_seguidas": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "criado_em": {
                      "type": "string"
                    },
                    "desativado_em": {
                      "nullable": true,
                      "type": "string"
                    },
                    "desativado_motivo": {
                      "nullable": true,
                      "type": "string"
                    },
                    "segredo": {
                      "nullable": true,
                      "description": "Devolvido UMA vez, na criação. Guarde-o: no banco existe apenas a versão cifrada, e não há como recuperá-lo. Num replay (`Idempotent-Replay: true`) vem SEMPRE `null` — o segredo nunca é gravado na tabela de idempotência. Quem perdeu a resposta original usa `POST /api/v1/webhooks/{id}/rotacao-segredo`, que emite um segredo novo.",
                      "type": "string"
                    }
                  },
                  "required": [
                    "id",
                    "url",
                    "descricao",
                    "eventos",
                    "ativo",
                    "falhas_seguidas",
                    "criado_em",
                    "desativado_em",
                    "desativado_motivo",
                    "segredo"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Chave de API inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "409": {
            "description": "Requisição em andamento · Chave de idempotência reutilizada",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "422": {
            "description": "URL de webhook inválida · Entrada inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        },
        "description": "Só `https`, e o host não pode resolver para endereço interno. O payload é mínimo por LGPD: evento, documento_id, referencia_externa, ambiente e ocorrido_em — sem CPF, e-mail, IP ou PDF.\n\n### Como verificar a assinatura\n\nToda entrega chega com três cabeçalhos, no padrão [Standard Webhooks](https://www.standardwebhooks.com/):\n\n| Cabeçalho | O que é |\n|---|---|\n| `webhook-id` | Identificador da entrega. **Estável entre retentativas** — use-o para deduplicar. |\n| `webhook-timestamp` | Unix time **em segundos** de quando a tentativa foi montada. |\n| `webhook-signature` | Uma ou mais assinaturas, separadas por espaço, cada uma no formato `v1,<base64>`. |\n\nA assinatura é `HMAC-SHA256` sobre a string `{webhook-id}.{webhook-timestamp}.{corpo cru}`, com a chave sendo o seu segredo **sem o prefixo `whsec_`**, decodificado de base64. O resultado vai em base64.\n\n⚠️ **Use o corpo CRU**, exatamente como chegou. Se você fizer `JSON.parse` e depois `JSON.stringify` para assinar, a ordem das chaves ou os espaços podem mudar e a assinatura nunca vai bater.\n\n```js\nimport { createHmac, timingSafeEqual } from 'node:crypto'\n\nfunction verificar(segredo, cabecalhos, corpoCru) {\n  const id = cabecalhos['webhook-id']\n  const ts = Number(cabecalhos['webhook-timestamp'])\n\n  // 1. Janela de 5 minutos, nos DOIS sentidos (relógio adiantado também).\n  if (Math.abs(Math.floor(Date.now() / 1000) - ts) > 300) return false\n\n  const chave = Buffer.from(segredo.replace(/^whsec_/, ''), 'base64')\n  const esperada = createHmac('sha256', chave)\n    .update(`${id}.${ts}.${corpoCru}`)\n    .digest('base64')\n\n  // 2. PODE VIR MAIS DE UMA: durante a rotação do segredo, as duas viajam\n  //    juntas. Aceite se QUALQUER uma bater.\n  return String(cabecalhos['webhook-signature'])\n    .split(' ')\n    .filter((p) => p.startsWith('v1,'))\n    .some((p) => {\n      const recebida = Buffer.from(p.slice(3))\n      const alvo = Buffer.from(esperada)\n      return recebida.length === alvo.length && timingSafeEqual(recebida, alvo)\n    })\n}\n```\n\n⚠️ **Compare em tempo constante** (`timingSafeEqual`, `hmac.compare` etc.). Comparação com `===` vaza, pelo tempo de resposta, quantos bytes iniciais bateram.\n\n⚠️ **Aceite mais de uma assinatura.** Ao rotacionar o segredo, o anterior continua válido por uma janela (24 h por padrão) e as duas assinaturas chegam juntas — é isso que permite trocar o segredo sem perder entrega. Um verificador que só olhe a primeira vai recusar metade das entregas durante a janela.\n\nPara exercitar tudo isso sem esperar um documento real, use `POST /api/v1/teste/webhooks/{id}/disparar` com uma chave de sandbox.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "maxLength": 500,
                    "format": "uri"
                  },
                  "descricao": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "eventos": {
                    "minItems": 1,
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "documento.assinado",
                        "documento.assinado_parcialmente",
                        "documento.recusado",
                        "documento.expirado",
                        "documento.cancelado",
                        "signatario.assinou",
                        "signatario.recusou"
                      ]
                    }
                  }
                },
                "required": [
                  "url",
                  "eventos"
                ]
              }
            }
          }
        },
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            },
            "description": "Obrigatória. ⚠️ Derivar a chave da referência externa é ótimo contra retentativa de rede e péssimo quando você quer reenviar o mesmo contrato de propósito: você recebe a resposta antiga. Para criar de novo, use um UUID v4 novo."
          }
        ],
        "security": [
          {
            "chaveDeApi": []
          }
        ]
      }
    },
    "/api/v1/webhooks/{id}/rotacao-segredo": {
      "post": {
        "operationId": "rotacionar_segredo_webhook",
        "summary": "Gera um segredo novo mantendo o antigo por 24 horas",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "Gera um segredo novo mantendo o antigo por 24 horas",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "endpoint_id": {
                      "type": "string"
                    },
                    "segredo": {
                      "nullable": true,
                      "description": "Devolvido UMA vez. Num replay (`Idempotent-Replay: true`) vem SEMPRE `null` — o segredo nunca é gravado na tabela de idempotência. Para obter outro, rotacione de novo com uma `Idempotency-Key` nova.",
                      "type": "string"
                    },
                    "segredo_anterior_expira_em": {
                      "nullable": true,
                      "type": "string"
                    }
                  },
                  "required": [
                    "endpoint_id",
                    "segredo",
                    "segredo_anterior_expira_em"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "401": {
            "description": "Chave de API inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "404": {
            "description": "Documento não encontrado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "409": {
            "description": "Requisição em andamento · Chave de idempotência reutilizada",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "422": {
            "description": "Entrada inválida",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        },
        "description": "Durante a janela, as duas assinaturas são enviadas em `webhook-signature`, separadas por espaço. Aceite qualquer uma das duas até terminar a troca do seu lado.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "janela_horas": {
                    "default": 24,
                    "description": "0 invalida o segredo antigo imediatamente.",
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 168
                  }
                }
              }
            }
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            },
            "description": "Obrigatória. ⚠️ Derivar a chave da referência externa é ótimo contra retentativa de rede e péssimo quando você quer reenviar o mesmo contrato de propósito: você recebe a resposta antiga. Para criar de novo, use um UUID v4 novo."
          }
        ],
        "security": [
          {
            "chaveDeApi": []
          }
        ]
      }
    },
    "/verificar/{hash}": {
      "get": {
        "operationId": "verificar_documento",
        "summary": "Verificação pública de um documento pelo hash final",
        "tags": [
          "Verificação"
        ],
        "responses": {
          "200": {
            "description": "Verificação pública de um documento pelo hash final",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "encontrado": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "documento": {
                      "type": "object",
                      "properties": {
                        "nome": {
                          "type": "string"
                        },
                        "status": {
                          "type": "string"
                        },
                        "criado_em": {
                          "type": "string"
                        },
                        "concluido_em": {
                          "nullable": true,
                          "type": "string"
                        },
                        "selado_em": {
                          "nullable": true,
                          "type": "string"
                        },
                        "montado_em": {
                          "nullable": true,
                          "type": "string"
                        },
                        "paginas": {
                          "nullable": true,
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991
                        },
                        "hash_final": {
                          "nullable": true,
                          "description": "SHA-256 do PDF montado. Compare com `shasum -a 256` do seu arquivo.",
                          "type": "string"
                        },
                        "eventos": {
                          "type": "integer",
                          "minimum": -9007199254740991,
                          "maximum": 9007199254740991,
                          "description": "Quantidade de elos na cadeia de evidências."
                        },
                        "cadeia_cabeca": {
                          "nullable": true,
                          "description": "SHA-256 em hex do último elo.",
                          "type": "string"
                        },
                        "ambiente": {
                          "type": "string",
                          "enum": [
                            "producao",
                            "teste"
                          ],
                          "description": "`teste` = documento gerado no ambiente de simulação (sandbox), sem valor probatório. Trate-o como não vinculante mesmo que a trilha esteja íntegra."
                        }
                      },
                      "required": [
                        "nome",
                        "status",
                        "criado_em",
                        "concluido_em",
                        "selado_em",
                        "montado_em",
                        "paginas",
                        "hash_final",
                        "eventos",
                        "cadeia_cabeca",
                        "ambiente"
                      ],
                      "additionalProperties": false
                    },
                    "nivel_tempo": {
                      "type": "string",
                      "enum": [
                        "nenhum",
                        "act_nao_credenciada",
                        "act_credenciada"
                      ]
                    },
                    "carimbo": {
                      "type": "boolean"
                    },
                    "signatarios": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "nome": {
                            "type": "string",
                            "description": "Primeiro nome e inicial do segundo."
                          },
                          "documento": {
                            "type": "string",
                            "description": "Mascarado."
                          },
                          "papel": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string"
                          },
                          "assinado_em": {
                            "nullable": true,
                            "type": "string"
                          }
                        },
                        "required": [
                          "nome",
                          "documento",
                          "papel",
                          "status",
                          "assinado_em"
                        ],
                        "additionalProperties": false
                      }
                    },
                    "aviso": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "encontrado",
                    "documento",
                    "nivel_tempo",
                    "carimbo",
                    "signatarios",
                    "aviso"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "404": {
            "description": "Documento não encontrado",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          },
          "429": {
            "description": "Limite de requisições excedido",
            "content": {
              "application/problem+json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "type": {
                      "type": "string",
                      "description": "Link para a página que explica como resolver."
                    },
                    "title": {
                      "type": "string"
                    },
                    "status": {
                      "type": "integer",
                      "minimum": -9007199254740991,
                      "maximum": 9007199254740991
                    },
                    "detail": {
                      "type": "string"
                    },
                    "instance": {
                      "type": "string"
                    },
                    "codigo": {
                      "type": "string",
                      "description": "Código estável. É por ele que o cliente ramifica — nunca pelo texto."
                    },
                    "requisicao_id": {
                      "type": "string",
                      "description": "Informe este valor ao suporte."
                    },
                    "erros": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "campo": {
                            "type": "string"
                          },
                          "mensagem": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "campo",
                          "mensagem"
                        ],
                        "additionalProperties": false
                      }
                    }
                  },
                  "required": [
                    "type",
                    "title",
                    "status",
                    "detail",
                    "instance",
                    "codigo",
                    "requisicao_id",
                    "erros"
                  ],
                  "additionalProperties": false
                }
              }
            }
          }
        },
        "description": "Rota pública. Aceita o `hash_final` (SHA-256 do PDF montado, 64 hex) ou o código de verificação impresso no QR (32 hex). NÃO aceita `hash_original`, para não virar oráculo. Nunca devolve o PDF — só metadados.",
        "parameters": [
          {
            "name": "hash",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    }
  }
}
