{
  "name": "EditalMD",
  "description": "Editais em Markdown, com prazos de proposta e impugnação, licitações salvas, alertas editáveis com filtros e prévia (termos ou CNPJ), vigias de mudança e lista de habilitação. Busca e prazos são grátis. Cada comprador paga $0.02 por página pelo próprio acesso, inclusive ao texto pronto, via x402/crédito ou depósito USDC. Geração necessária incluída. Exemplos livres; piloto individual oferece um premium e 100 básicos até 50 páginas com X-Agent-Pass (/api/avaliacao, guia /avaliacao.md), sujeito a validade, capacidade e orçamento. Básico não revisado; premium não equivale a aprovação de fidelidade. Conta opcional em /conta/global; /api/me/documentos e /compras são privados. Compra autenticada vincula automaticamente; a anônima pode ser vinculada em POST /api/documento/:id/vincular com sessão e X-Editalmd-Acesso. Depois do vínculo só a conta abre. Sem vínculo, guarde acesso.codigo. GET nunca inicia geração.",
  "build": "b5c2405c",
  "base_url": "https://editalmd.com",
  "docs": {
    "llms": "https://editalmd.com/llms.txt",
    "llms_full": "https://editalmd.com/llms-full.txt",
    "openapi": "https://editalmd.com/openapi.json",
    "mcp": "https://editalmd.com/mcp",
    "pricing": "https://editalmd.com/api/pricing",
    "billing": "https://editalmd.com/api/billing",
    "human_ui": "https://editalmd.com/",
    "data_indexes": [
      {
        "id": "cep",
        "produto": "https://pontofato.com",
        "caminho": "/enderecos",
        "title": "CEPs e endereços",
        "description": "Encontre endereços por lugar, com coordenadas e referência de 2022. Não certifica CEP vigente. Cada página HTML abre o app do produto com os dados públicos já renderizados.",
        "hierarchy": "UF → município → bairro/localidade → rua → endereços",
        "url": "https://pontofato.com/enderecos/",
        "formats": {
          "html": "https://pontofato.com/enderecos/",
          "json": "https://api.pontofato.com/enderecos/index.json",
          "md": "https://api.pontofato.com/enderecos/index.md",
          "okf": "https://api.pontofato.com/enderecos/index.okf.md"
        },
        "llms": "https://api.pontofato.com/enderecos/llms.txt",
        "openapi": "https://api.pontofato.com/enderecos/openapi.json",
        "mcp": "https://api.pontofato.com/enderecos/mcp",
        "okf": "https://api.pontofato.com/enderecos/okf/index.md",
        "access": "public-read-only",
        "pagination": {
          "max_items": 20,
          "next": "links.proximo"
        },
        "updates": "manual"
      },
      {
        "id": "editais",
        "produto": "https://editalmd.com",
        "caminho": "/licitacoes",
        "title": "Editais e compras públicas",
        "description": "Encontre compras públicas por lugar e período. Consulte documentos e opções de leitura no EditalMD. Cada página HTML abre o app do produto com os dados públicos já renderizados.",
        "hierarchy": "Modalidade → UF → ano → mês → dia → município → compras",
        "url": "https://editalmd.com/licitacoes/",
        "formats": {
          "html": "https://editalmd.com/licitacoes/",
          "json": "https://api.editalmd.com/licitacoes/index.json",
          "md": "https://api.editalmd.com/licitacoes/index.md",
          "okf": "https://api.editalmd.com/licitacoes/index.okf.md"
        },
        "llms": "https://api.editalmd.com/licitacoes/llms.txt",
        "openapi": "https://api.editalmd.com/licitacoes/openapi.json",
        "mcp": "https://api.editalmd.com/licitacoes/mcp",
        "okf": "https://api.editalmd.com/licitacoes/okf/index.md",
        "access": "public-read-only",
        "pagination": {
          "max_items": 20,
          "next": "links.proximo"
        },
        "updates": "manual"
      }
    ]
  },
  "conventions": {
    "format": "JSON em `/api/*`; o documento sai em `text/markdown`.",
    "cors": "`Access-Control-Allow-Origin: *` nas rotas de agente.",
    "x402": "Cada comprador paga $0.02 por página pelo próprio acesso, inclusive ao texto pronto, via x402/crédito ou depósito USDC. Geração necessária incluída. Exemplos livres; piloto individual oferece um premium e 100 básicos até 50 páginas com X-Agent-Pass (/api/avaliacao, guia /avaliacao.md), sujeito a validade, capacidade e orçamento. Básico não revisado; premium não equivale a aprovação de fidelidade. Conta opcional em /conta/global; /api/me/documentos e /compras são privados. Compra autenticada vincula automaticamente; a anônima pode ser vinculada em POST /api/documento/:id/vincular com sessão e X-Editalmd-Acesso. Depois do vínculo só a conta abre. Sem vínculo, guarde acesso.codigo. GET nunca inicia geração.",
    "prova": "Markdown pronto traz SHA-256. Geração paga traz o recibo x402/crédito em pagamento; recibos históricos seguem em /api/recibo/{id}.",
    "parity": "Mexeu na UI/API → apidocs + skill + MCP no mesmo PR."
  },
  "auth": {
    "session": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada.",
    "none": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago.",
    "credito": "Token de crédito em `Authorization: Bearer cred_…` (ou `X-Credito`). Para saldo recuperado de x402, use a credencial de carteira `mmw_…` em Bearer ou `X-Wallet-Token`, emitida por `/api/auth/wallet/agent/start` e `/api/auth/wallet/agent/token`.",
    "agente": "X-Agent-Pass da inscrição em api.editalmd.com/licitacoes/api/agente. Concessão individual temporária; sem conta humana ou pagamento.",
    "acesso": "Sessão da conta com aquisição vinculada, X-Editalmd-Acesso de compra anônima, ou X-Editalmd-Avaliacao junto de X-Agent-Pass para o documento patrocinado. Depois do vínculo da compra, exige conta. Os exemplos são livres.",
    "owner": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404.",
    "cobranca": "X-Cobranca: token de 64 hex minúsculos escolhido aleatoriamente pelo cliente; conserve para consultar e retomar sua cobrança.",
    "origem": "X-Editalmd-Secret: credencial privada de integração interna. Não é uma porta para clientes ou agentes públicos."
  },
  "regime": "Cada comprador paga $0.02 por página pelo próprio acesso, inclusive ao texto pronto, via x402/crédito ou depósito USDC. Geração necessária incluída. Exemplos livres; piloto individual oferece um premium e 100 básicos até 50 páginas com X-Agent-Pass (/api/avaliacao, guia /avaliacao.md), sujeito a validade, capacidade e orçamento. Básico não revisado; premium não equivale a aprovação de fidelidade. Conta opcional em /conta/global; /api/me/documentos e /compras são privados. Compra autenticada vincula automaticamente; a anônima pode ser vinculada em POST /api/documento/:id/vincular com sessão e X-Editalmd-Acesso. Depois do vínculo só a conta abre. Sem vínculo, guarde acesso.codigo. GET nunca inicia geração.",
  "gratis_acima_de_dias": 0,
  "pago": {
    "POST /api/documento/{id}/geracao": "$0.02",
    "POST /api/documento/{id}/habilitacao (recente)": "$0.00",
    "POST /api/alertas (além do 1º, 30 dias)": "$0.10",
    "POST /api/vigias (além da 1ª)": "$0.05"
  },
  "pagamento": {
    "por_requisicao": "x402 (HTTP 402 + X-PAYMENT), sem cadastro",
    "credito_pre_pago": {
      "recarregar": "https://editalmd.com/api/credito",
      "pacotes_usd": [
        1,
        5,
        10,
        25
      ],
      "usar": "Authorization: Bearer cred_…",
      "vale_em": "todos os produtos da casa"
    }
  },
  "endpoints": [
    {
      "method": "GET",
      "path": "/api/ref",
      "auth": "none",
      "grupo": "Consulta",
      "summary": "Pesquisa nomes de municípios, atividades e outras referências do Radar CNPJ.",
      "query": {
        "tipo": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "municipio, cnae, natureza, qualificacao, pais ou motivo."
        },
        "q": {
          "tipo": "string",
          "desc": "Duas a 60 letras. Opcional quando há códigos."
        },
        "codigos": {
          "tipo": "string",
          "desc": "Até 50 códigos da Receita, separados por vírgula. Não são códigos IBGE."
        },
        "limit": {
          "tipo": "int",
          "desc": "De 1 a 50 resultados; padrão 20."
        }
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "True when the reference lookup succeeds."
        },
        "results": {
          "tipo": "object[]",
          "desc": "Referências com codigo, descricao e, para município, uf. Para filtrar licitações, use o nome e a UF."
        }
      },
      "erros": {
        "400": "Tipo ou busca inválidos.",
        "429": "Limite da origem.",
        "503": "Referência indisponível."
      },
      "exemplo": "curl -s '$ORIGIN/api/ref?tipo=municipio&q=Campinas'",
      "returns": "{ ok, results }",
      "url": "https://editalmd.com/api/ref",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/avaliacao",
      "auth": "agente",
      "grupo": "Avaliação",
      "summary": "Cotas documentais deste agente: um premium patrocinado e 100 leituras básicas.",
      "headers": {
        "X-Agent-Pass": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Credencial individual persistente obtida em POST https://api.editalmd.com/licitacoes/api/agente. Não é User-Agent."
        }
      },
      "erros": {
        "400": "Campos ou consulta desconhecidos; POST aceita corpo ausente ou {}.",
        "401": "Credencial de agente ausente ou inválida.",
        "402": "Cota individual usada ou expirada; veja purchase_url para comprar.",
        "404": "Documento ou solicitação deste agente inexistente.",
        "409": "Fonte ou cotação indisponível/alterada; nenhuma cobrança.",
        "422": "Premium até 50 páginas; básico PDF até 50 páginas e 32 MiB.",
        "503": "Piloto encerrado, orçamento esgotado ou fila sem capacidade; preserve a credencial e tente depois."
      },
      "retorno": {
        "expires_at": {
          "tipo": "string",
          "desc": "Fim da concessão individual, limitado pelo piloto."
        },
        "premium": {
          "tipo": "object",
          "desc": "granted:1, used, document_id e max_pages:50."
        },
        "basic": {
          "tipo": "object",
          "desc": "granted:100, used, max_pages:50 e reviewed:false."
        }
      },
      "exemplo": "curl -s $ORIGIN/api/avaliacao -H \"X-Agent-Pass: $AGENT_PASS\"",
      "returns": "{ expires_at, premium, basic }",
      "url": "https://editalmd.com/api/avaliacao",
      "auth_detail": "X-Agent-Pass da inscrição em api.editalmd.com/licitacoes/api/agente. Concessão individual temporária; sem conta humana ou pagamento."
    },
    {
      "method": "POST",
      "path": "/api/documento/:id/avaliacao/premium",
      "auth": "agente",
      "grupo": "Avaliação",
      "summary": "Concede um documento premium por agente; gera se necessário, sem cobrar o agente.",
      "headers": {
        "X-Agent-Pass": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Credencial individual persistente obtida em POST https://api.editalmd.com/licitacoes/api/agente. Não é User-Agent."
        }
      },
      "params": {
        "id": {
          "desc": "ID positivo do documento do acervo.",
          "exemplo": "9927611"
        }
      },
      "retorno": {
        "documento_id": {
          "tipo": "int",
          "desc": "Documento solicitado."
        },
        "status": {
          "tipo": "string",
          "desc": "ready, pending, running ou failed; access_granted recupera a concessão premium, sem afirmar processamento concluído. Preparação premium também pode trazer error.",
          "opcional": true
        },
        "error": {
          "tipo": "string",
          "desc": "Causa da falha, quando houver.",
          "nulo": true,
          "opcional": true
        },
        "retry_after_s": {
          "tipo": "int",
          "desc": "Intervalo para o próximo GET.",
          "opcional": true
        },
        "evaluation": {
          "tipo": "object",
          "desc": "kind basic ou sponsored_premium. Premium inclui access_code privado, access_header e expires_at; cobrança zero."
        },
        "state_url": {
          "tipo": "string",
          "desc": "GET de acompanhamento do premium, com os dois headers de avaliação.",
          "opcional": true
        },
        "result": {
          "tipo": "object",
          "desc": "Somente básico pronto: pages [{page,text}], page_count, ocr_page_count, source_sha256, reviewed:false, structured_tables:false e empty_pages.",
          "opcional": true
        }
      },
      "erros": {
        "400": "Campos ou consulta desconhecidos; POST aceita corpo ausente ou {}.",
        "401": "Credencial de agente ausente ou inválida.",
        "402": "Cota individual usada ou expirada; veja purchase_url para comprar.",
        "404": "Documento ou solicitação deste agente inexistente.",
        "409": "Fonte ou cotação indisponível/alterada; nenhuma cobrança.",
        "422": "Premium até 50 páginas; básico PDF até 50 páginas e 32 MiB.",
        "503": "Piloto encerrado, orçamento esgotado ou fila sem capacidade; preserve a credencial e tente depois."
      },
      "desc": "Franquia por credencial, até a menor data entre os 30 dias do agente e o fim do piloto. Repetição do mesmo documento não consome outra unidade. Não envie pagamento. Premium: guarde evaluation.access_code e use X-Editalmd-Avaliacao junto de X-Agent-Pass nas leituras e no GET /geracao. Básico não abre conteúdo premium. Piloto sujeito ao orçamento global; sem renovação automática.",
      "exemplo": "curl -s -X POST $ORIGIN/api/documento/9927611/avaliacao/premium -H \"X-Agent-Pass: $AGENT_PASS\"",
      "returns": "{ documento_id, status?, error?, retry_after_s?, evaluation, state_url?, result? }",
      "url": "https://editalmd.com/api/documento/:id/avaliacao/premium",
      "auth_detail": "X-Agent-Pass da inscrição em api.editalmd.com/licitacoes/api/agente. Concessão individual temporária; sem conta humana ou pagamento."
    },
    {
      "method": "POST",
      "path": "/api/documento/:id/avaliacao/basico",
      "auth": "agente",
      "grupo": "Avaliação",
      "summary": "Enfileira uma leitura básica individual: texto nativo e OCR local, sem revisão.",
      "headers": {
        "X-Agent-Pass": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Credencial individual persistente obtida em POST https://api.editalmd.com/licitacoes/api/agente. Não é User-Agent."
        }
      },
      "params": {
        "id": {
          "desc": "ID positivo do documento do acervo.",
          "exemplo": "9927611"
        }
      },
      "retorno": {
        "documento_id": {
          "tipo": "int",
          "desc": "Documento solicitado."
        },
        "status": {
          "tipo": "string",
          "desc": "ready, pending, running ou failed; access_granted recupera a concessão premium, sem afirmar processamento concluído. Preparação premium também pode trazer error.",
          "opcional": true
        },
        "error": {
          "tipo": "string",
          "desc": "Causa da falha, quando houver.",
          "nulo": true,
          "opcional": true
        },
        "retry_after_s": {
          "tipo": "int",
          "desc": "Intervalo para o próximo GET.",
          "opcional": true
        },
        "evaluation": {
          "tipo": "object",
          "desc": "kind basic ou sponsored_premium. Premium inclui access_code privado, access_header e expires_at; cobrança zero."
        },
        "state_url": {
          "tipo": "string",
          "desc": "GET de acompanhamento do premium, com os dois headers de avaliação.",
          "opcional": true
        },
        "result": {
          "tipo": "object",
          "desc": "Somente básico pronto: pages [{page,text}], page_count, ocr_page_count, source_sha256, reviewed:false, structured_tables:false e empty_pages.",
          "opcional": true
        }
      },
      "erros": {
        "400": "Campos ou consulta desconhecidos; POST aceita corpo ausente ou {}.",
        "401": "Credencial de agente ausente ou inválida.",
        "402": "Cota individual usada ou expirada; veja purchase_url para comprar.",
        "404": "Documento ou solicitação deste agente inexistente.",
        "409": "Fonte ou cotação indisponível/alterada; nenhuma cobrança.",
        "422": "Premium até 50 páginas; básico PDF até 50 páginas e 32 MiB.",
        "503": "Piloto encerrado, orçamento esgotado ou fila sem capacidade; preserve a credencial e tente depois."
      },
      "desc": "Franquia por credencial, até a menor data entre os 30 dias do agente e o fim do piloto. Repetição do mesmo documento não consome outra unidade. Não envie pagamento. Premium: guarde evaluation.access_code e use X-Editalmd-Avaliacao junto de X-Agent-Pass nas leituras e no GET /geracao. Básico não abre conteúdo premium. Piloto sujeito ao orçamento global; sem renovação automática.",
      "exemplo": "curl -s -X POST $ORIGIN/api/documento/9927611/avaliacao/basico -H \"X-Agent-Pass: $AGENT_PASS\"",
      "returns": "{ documento_id, status?, error?, retry_after_s?, evaluation, state_url?, result? }",
      "url": "https://editalmd.com/api/documento/:id/avaliacao/basico",
      "auth_detail": "X-Agent-Pass da inscrição em api.editalmd.com/licitacoes/api/agente. Concessão individual temporária; sem conta humana ou pagamento."
    },
    {
      "method": "GET",
      "path": "/api/documento/:id/avaliacao/basico",
      "auth": "agente",
      "grupo": "Avaliação",
      "summary": "Recupera estado e texto básico por página, somente para o agente que solicitou.",
      "headers": {
        "X-Agent-Pass": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Credencial individual persistente obtida em POST https://api.editalmd.com/licitacoes/api/agente. Não é User-Agent."
        }
      },
      "params": {
        "id": {
          "desc": "ID positivo do documento do acervo.",
          "exemplo": "9927611"
        }
      },
      "retorno": {
        "documento_id": {
          "tipo": "int",
          "desc": "Documento solicitado."
        },
        "status": {
          "tipo": "string",
          "desc": "ready, pending, running ou failed; access_granted recupera a concessão premium, sem afirmar processamento concluído. Preparação premium também pode trazer error.",
          "opcional": true
        },
        "error": {
          "tipo": "string",
          "desc": "Causa da falha, quando houver.",
          "nulo": true,
          "opcional": true
        },
        "retry_after_s": {
          "tipo": "int",
          "desc": "Intervalo para o próximo GET.",
          "opcional": true
        },
        "evaluation": {
          "tipo": "object",
          "desc": "kind basic ou sponsored_premium. Premium inclui access_code privado, access_header e expires_at; cobrança zero."
        },
        "state_url": {
          "tipo": "string",
          "desc": "GET de acompanhamento do premium, com os dois headers de avaliação.",
          "opcional": true
        },
        "result": {
          "tipo": "object",
          "desc": "Somente básico pronto: pages [{page,text}], page_count, ocr_page_count, source_sha256, reviewed:false, structured_tables:false e empty_pages.",
          "opcional": true
        }
      },
      "erros": {
        "400": "Campos ou consulta desconhecidos; POST aceita corpo ausente ou {}.",
        "401": "Credencial de agente ausente ou inválida.",
        "402": "Cota individual usada ou expirada; veja purchase_url para comprar.",
        "404": "Documento ou solicitação deste agente inexistente.",
        "409": "Fonte ou cotação indisponível/alterada; nenhuma cobrança.",
        "422": "Premium até 50 páginas; básico PDF até 50 páginas e 32 MiB.",
        "503": "Piloto encerrado, orçamento esgotado ou fila sem capacidade; preserve a credencial e tente depois."
      },
      "desc": "Franquia por credencial, até a menor data entre os 30 dias do agente e o fim do piloto. Repetição do mesmo documento não consome outra unidade. Não envie pagamento. Premium: guarde evaluation.access_code e use X-Editalmd-Avaliacao junto de X-Agent-Pass nas leituras e no GET /geracao. Básico não abre conteúdo premium. Piloto sujeito ao orçamento global; sem renovação automática.",
      "exemplo": "curl -s -X GET $ORIGIN/api/documento/9927611/avaliacao/basico -H \"X-Agent-Pass: $AGENT_PASS\"",
      "returns": "{ documento_id, status?, error?, retry_after_s?, evaluation, state_url?, result? }",
      "url": "https://editalmd.com/api/documento/:id/avaliacao/basico",
      "auth_detail": "X-Agent-Pass da inscrição em api.editalmd.com/licitacoes/api/agente. Concessão individual temporária; sem conta humana ou pagamento."
    },
    {
      "method": "GET",
      "path": "/api/me/empresas/:cnpj/documentos",
      "summary": "Lista os anexos privados da empresa; não inicia leitura ou análise.",
      "auth": "owner",
      "grupo": "Análise de participação",
      "params": {
        "cnpj": {
          "desc": "CNPJ de 14 caracteres (dígitos ou alfanumérico) vinculado ao dono.",
          "exemplo": "00394460000141"
        }
      },
      "erros": {
        "400": "Entrada inválida.",
        "401": "Sessão da conta ou convidado válido necessário.",
        "402": "Acesso ao edital necessário.",
        "403": "Origem recusada.",
        "404": "Empresa ou documento ausente para este dono.",
        "409": "Fontes ou checkpoint indisponíveis.",
        "413": "Limite de documentos, páginas ou bytes.",
        "429": "Processamento em curso; tente depois.",
        "502": "Core indisponível.",
        "503": "Configuração ou orçamento de processamento indisponível."
      },
      "exemplo": "curl -s -X GET '$ORIGIN/api/me/empresas/00394460000141/documentos' -H 'X-Guest-Token: $GUEST'",
      "retorno": "DocumentosEmpresa",
      "returns": "{ itens[{id,nome,tipo,bytes,paginas,enviado_em}], revisao, limite, limite_bytes, limite_paginas }",
      "url": "https://editalmd.com/api/me/empresas/:cnpj/documentos",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "POST",
      "path": "/api/me/empresas/:cnpj/documentos",
      "summary": "Adiciona PDF de atestado, certidão ou outro comprovante à empresa.",
      "auth": "owner",
      "grupo": "Análise de participação",
      "params": {
        "cnpj": {
          "desc": "CNPJ de 14 caracteres (dígitos ou alfanumérico) vinculado ao dono.",
          "exemplo": "00394460000141"
        }
      },
      "erros": {
        "400": "Entrada inválida.",
        "401": "Sessão da conta ou convidado válido necessário.",
        "402": "Acesso ao edital necessário.",
        "403": "Origem recusada.",
        "404": "Empresa ou documento ausente para este dono.",
        "409": "Fontes ou checkpoint indisponíveis.",
        "413": "Limite de documentos, páginas ou bytes.",
        "429": "Processamento em curso; tente depois.",
        "502": "Core indisponível.",
        "503": "Configuração ou orçamento de processamento indisponível."
      },
      "exemplo": "curl -s '$ORIGIN/api/me/empresas/00394460000141/documentos' -H 'Authorization: Bearer $SESS' -H 'Content-Type: application/json' --data-binary @anexo.json",
      "desc": "201. JSON até 11.200.000 bytes; PDF até 8 MiB, 20 documentos/80 MiB/50 páginas por empresa. Arquivo idêntico é reaproveitado. A leitura automática acontece somente ao solicitar a análise.",
      "corpo": {
        "nome": {
          "tipo": "string",
          "desc": "Nome até 160 caracteres."
        },
        "tipo": {
          "tipo": "string",
          "desc": "atestado, certidao, licenca, contrato_social ou outro."
        },
        "arquivo_base64": {
          "tipo": "string",
          "desc": "PDF em base64 canônico, sem prefixo data:. Prefira envio HTTP a partir do arquivo local."
        }
      },
      "retorno": "DocumentosEmpresa",
      "returns": "{ itens[{id,nome,tipo,bytes,paginas,enviado_em}], revisao, limite, limite_bytes, limite_paginas }",
      "url": "https://editalmd.com/api/me/empresas/:cnpj/documentos",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "GET",
      "path": "/api/me/empresas/:cnpj/documentos/:arquivo",
      "summary": "Baixa o PDF privado, sem chamada de IA.",
      "auth": "owner",
      "grupo": "Análise de participação",
      "params": {
        "cnpj": {
          "desc": "CNPJ de 14 caracteres (dígitos ou alfanumérico) vinculado ao dono.",
          "exemplo": "00394460000141"
        },
        "arquivo": {
          "desc": "SHA-256 retornado no envio.",
          "exemplo": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
        }
      },
      "erros": {
        "400": "Entrada inválida.",
        "401": "Sessão da conta ou convidado válido necessário.",
        "402": "Acesso ao edital necessário.",
        "403": "Origem recusada.",
        "404": "Empresa ou documento ausente para este dono.",
        "409": "Fontes ou checkpoint indisponíveis.",
        "413": "Limite de documentos, páginas ou bytes.",
        "429": "Processamento em curso; tente depois.",
        "502": "Core indisponível.",
        "503": "Configuração ou orçamento de processamento indisponível."
      },
      "exemplo": "curl -s -X GET '$ORIGIN/api/me/empresas/00394460000141/documentos/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' -H 'X-Guest-Token: $GUEST'",
      "retorno": {
        "_texto": "PDF binário com Content-Disposition: attachment; use HTTP autenticado para baixar."
      },
      "returns": "PDF binário com Content-Disposition: attachment; use HTTP autenticado para baixar.",
      "url": "https://editalmd.com/api/me/empresas/:cnpj/documentos/:arquivo",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "DELETE",
      "path": "/api/me/empresas/:cnpj/documentos/:arquivo",
      "summary": "Remove o anexo desta empresa e invalida a análise que o utilizou.",
      "auth": "owner",
      "grupo": "Análise de participação",
      "params": {
        "cnpj": {
          "desc": "CNPJ de 14 caracteres (dígitos ou alfanumérico) vinculado ao dono.",
          "exemplo": "00394460000141"
        },
        "arquivo": {
          "desc": "SHA-256 do anexo.",
          "exemplo": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
        }
      },
      "erros": {
        "400": "Entrada inválida.",
        "401": "Sessão da conta ou convidado válido necessário.",
        "402": "Acesso ao edital necessário.",
        "403": "Origem recusada.",
        "404": "Empresa ou documento ausente para este dono.",
        "409": "Fontes ou checkpoint indisponíveis.",
        "413": "Limite de documentos, páginas ou bytes.",
        "429": "Processamento em curso; tente depois.",
        "502": "Core indisponível.",
        "503": "Configuração ou orçamento de processamento indisponível."
      },
      "exemplo": "curl -s -X DELETE '$ORIGIN/api/me/empresas/00394460000141/documentos/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' -H 'X-Guest-Token: $GUEST'",
      "retorno": "DocumentosEmpresa",
      "returns": "{ itens[{id,nome,tipo,bytes,paginas,enviado_em}], revisao, limite, limite_bytes, limite_paginas }",
      "url": "https://editalmd.com/api/me/empresas/:cnpj/documentos/:arquivo",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "POST",
      "path": "/api/me/empresas/:cnpj/analises/:id",
      "summary": "Inicia ou retoma comparação de requisitos, atestados e obrigações com a empresa.",
      "auth": "owner",
      "grupo": "Análise de participação",
      "params": {
        "cnpj": {
          "desc": "CNPJ de 14 caracteres (dígitos ou alfanumérico) vinculado ao dono.",
          "exemplo": "00394460000141"
        },
        "id": {
          "desc": "ID do documento com dossiê pronto e acesso autorizado.",
          "exemplo": 1993401
        }
      },
      "erros": {
        "400": "Entrada inválida.",
        "401": "Sessão da conta ou convidado válido necessário.",
        "402": "Acesso ao edital necessário.",
        "403": "Origem recusada.",
        "404": "Empresa ou documento ausente para este dono.",
        "409": "Fontes ou checkpoint indisponíveis.",
        "413": "Limite de documentos, páginas ou bytes.",
        "429": "Processamento em curso; tente depois.",
        "502": "Core indisponível.",
        "503": "Configuração ou orçamento de processamento indisponível."
      },
      "exemplo": "curl -s -X POST '$ORIGIN/api/me/empresas/00394460000141/analises/1993401?v=HASH_DO_MARKDOWN' -H 'Authorization: Bearer $SESS'",
      "query": {
        "v": {
          "tipo": "string",
          "desc": "SHA-256 do Markdown aberto, 64 hex minúsculos.",
          "obrigatorio": true
        }
      },
      "desc": "202 após aceitar e preservar o pedido; 200 ao reaproveitar análise concluída. Usa perfil e anexos deste dono. Pedidos interrompidos podem ser retomados; falhas informam motivo e próxima ação. POST explícito retoma uma pausa. Até 2 mil fatos e 100 editais por empresa, sujeitos à capacidade e ao orçamento disponíveis. Não cobra nova compra nesta operação. Acompanhamento somente por GET. A análise oferece triagem com evidências, não decisão definitiva de habilitação nem consulta jurídica externa.",
      "retorno": {
        "analise": {
          "tipo": "object",
          "desc": "Estado inicial: id, status, etapa, processados, total, CNPJ, hashes e datas."
        }
      },
      "returns": "{ analise }",
      "url": "https://editalmd.com/api/me/empresas/:cnpj/analises/:id",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "GET",
      "path": "/api/me/empresas/:cnpj/analises/:id",
      "summary": "Consulta andamento ou resultados paginados; não inicia IA nem modifica a análise.",
      "auth": "owner",
      "grupo": "Análise de participação",
      "params": {
        "cnpj": {
          "desc": "CNPJ de 14 caracteres (dígitos ou alfanumérico) vinculado ao dono.",
          "exemplo": "00394460000141"
        },
        "id": {
          "desc": "ID do documento.",
          "exemplo": 1993401
        }
      },
      "erros": {
        "400": "Entrada inválida.",
        "401": "Sessão da conta ou convidado válido necessário.",
        "402": "Acesso ao edital necessário.",
        "403": "Origem recusada.",
        "404": "Empresa ou documento ausente para este dono.",
        "409": "Fontes ou checkpoint indisponíveis.",
        "413": "Limite de documentos, páginas ou bytes.",
        "429": "Processamento em curso; tente depois.",
        "502": "Core indisponível.",
        "503": "Configuração ou orçamento de processamento indisponível."
      },
      "exemplo": "curl -s '$ORIGIN/api/me/empresas/00394460000141/analises/1993401?v=HASH_DO_MARKDOWN&grupo=pendencias&limit=30' -H 'Authorization: Bearer $SESS'",
      "query": {
        "v": {
          "tipo": "string",
          "desc": "SHA-256 do Markdown aberto, 64 hex minúsculos.",
          "obrigatorio": true
        },
        "grupo": {
          "tipo": "string",
          "desc": "pendencias, atendidos ou nao_aplicavel; omitido retorna todos."
        },
        "kind": {
          "tipo": "string",
          "desc": "requirement, attestation ou obligation."
        },
        "after": {
          "tipo": "int",
          "desc": "Último ID recebido; padrão 0."
        },
        "limit": {
          "tipo": "int",
          "desc": "1 a 30; padrão 30."
        }
      },
      "desc": "Pendências reúne precisa_comprovar (falta prova), divergente (evidência incompatível) e acompanhar (obrigação futura). Cadastro, anexos ou dossiê diferentes retornam outdated sem resultados atuais. A data de referência é conservada na retomada; dia anterior retorna data_atual=false. Os lotes validados continuam disponíveis durante falhas/processamento com parcial=true e processados/total; nunca representam conclusão das exigências ainda não comparadas. GET não executa a fila nem inicia IA.",
      "retorno": "AnaliseParticipacao",
      "returns": "{ analise, itens, contagens?, tipos?, next }",
      "url": "https://editalmd.com/api/me/empresas/:cnpj/analises/:id",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "GET",
      "path": "/api/me/empresas",
      "summary": "Lista as empresas de quem pede (as organizações da conta com o EditalMD) e a escolhida; sem conta, vem vazia.",
      "auth": "owner",
      "grupo": "Empresas",
      "retorno": "EmpresasConta",
      "erros": {
        "400": "CNPJ ou busca inválida.",
        "401": "Conta necessária (conta_necessaria) ou sessão encerrada; a busca aceita o convidado.",
        "403": "Origem recusada, chave da conta (organization_key_required), papel sem gestão (organization_role_required) ou compartilhada sem 2FA (organization_mfa_required).",
        "404": "Empresa ausente nas organizações de quem pede, ou CNPJ ausente na base.",
        "405": "Método não permitido.",
        "409": "Limite de 100 empresas, organização indicada que já tem empresa, ou organização da qual quem pede saiu.",
        "429": "Teto de organizações novas da conta.",
        "503": "Origem, conta ou orçamento indisponível."
      },
      "exemplo": "curl -s -X GET '$ORIGIN/api/me/empresas' -H 'X-Api-Key: $CHAVE_DA_ORGANIZACAO'",
      "returns": "{ itens[{cnpj,razao_social,nome_fantasia,situacao,situacao_desde,porte,natureza_juridica,inicio_atividade,matriz_filial,capital_social,municipio,uf,cnaes,fonte,importado_em,organizacao}], selecionada, selecionada_organizacao, limite, conta_necessaria }",
      "url": "https://editalmd.com/api/me/empresas",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "GET",
      "path": "/api/me/empresas/busca",
      "summary": "Busca até oito sugestões por razão social ou CNPJ completo; não cadastra.",
      "auth": "owner",
      "grupo": "Empresas",
      "retorno": {
        "itens": {
          "tipo": "SugestaoEmpresa[]",
          "desc": "Até oito resultados; refine a busca quando necessário."
        }
      },
      "erros": {
        "400": "CNPJ ou busca inválida.",
        "401": "Conta necessária (conta_necessaria) ou sessão encerrada; a busca aceita o convidado.",
        "403": "Origem recusada, chave da conta (organization_key_required), papel sem gestão (organization_role_required) ou compartilhada sem 2FA (organization_mfa_required).",
        "404": "Empresa ausente nas organizações de quem pede, ou CNPJ ausente na base.",
        "405": "Método não permitido.",
        "409": "Limite de 100 empresas, organização indicada que já tem empresa, ou organização da qual quem pede saiu.",
        "429": "Teto de organizações novas da conta.",
        "503": "Origem, conta ou orçamento indisponível."
      },
      "exemplo": "curl -s '$ORIGIN/api/me/empresas/busca?q=padaria' -H 'X-Guest-Token: $GUEST'",
      "query": {
        "q": {
          "tipo": "string",
          "desc": "CNPJ com ou sem pontuação ou razão social, de 3 a 120 caracteres.",
          "obrigatorio": true
        }
      },
      "returns": "{ itens[{cnpj,nome,municipio,uf,situacao}] }",
      "url": "https://editalmd.com/api/me/empresas/busca",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "PUT",
      "path": "/api/me/empresas/:cnpj",
      "summary": "Importa os dados cadastrais numa organização da conta.",
      "auth": "owner",
      "grupo": "Empresas",
      "retorno": "EmpresasConta",
      "erros": {
        "400": "CNPJ ou busca inválida.",
        "401": "Conta necessária (conta_necessaria) ou sessão encerrada; a busca aceita o convidado.",
        "403": "Origem recusada, chave da conta (organization_key_required), papel sem gestão (organization_role_required) ou compartilhada sem 2FA (organization_mfa_required).",
        "404": "Empresa ausente nas organizações de quem pede, ou CNPJ ausente na base.",
        "405": "Método não permitido.",
        "409": "Limite de 100 empresas, organização indicada que já tem empresa, ou organização da qual quem pede saiu.",
        "429": "Teto de organizações novas da conta.",
        "503": "Origem, conta ou orçamento indisponível."
      },
      "exemplo": "curl -s -X PUT '$ORIGIN/api/me/empresas/00394460000141' -H 'X-Api-Key: $CHAVE_DA_ORGANIZACAO'",
      "params": {
        "cnpj": {
          "desc": "CNPJ completo, 14 dígitos com verificação válida.",
          "exemplo": "00394460000141"
        }
      },
      "desc": "Sem X-Organization-Id, cria a organização com a razão social e o EditalMD ligado, ou devolve a que a pessoa tirou da lista (201). Com X-Organization-Id ou chave de organização, a ficha vai para essa organização, se quem pede a gere e ela não tem empresa. 200 quando o CNPJ já está numa organização de quem pede. Até 100 empresas; sem sócios ou contatos; nenhuma análise é iniciada.",
      "returns": "{ itens[{cnpj,razao_social,nome_fantasia,situacao,situacao_desde,porte,natureza_juridica,inicio_atividade,matriz_filial,capital_social,municipio,uf,cnaes,fonte,importado_em,organizacao}], selecionada, selecionada_organizacao, limite, conta_necessaria }",
      "url": "https://editalmd.com/api/me/empresas/:cnpj",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "PUT",
      "path": "/api/me/empresas/:cnpj/selecionar",
      "summary": "Seleciona uma empresa já cadastrada para trabalhar no edital.",
      "auth": "owner",
      "grupo": "Empresas",
      "retorno": "EmpresasConta",
      "erros": {
        "400": "CNPJ ou busca inválida.",
        "401": "Conta necessária (conta_necessaria) ou sessão encerrada; a busca aceita o convidado.",
        "403": "Origem recusada, chave da conta (organization_key_required), papel sem gestão (organization_role_required) ou compartilhada sem 2FA (organization_mfa_required).",
        "404": "Empresa ausente nas organizações de quem pede, ou CNPJ ausente na base.",
        "405": "Método não permitido.",
        "409": "Limite de 100 empresas, organização indicada que já tem empresa, ou organização da qual quem pede saiu.",
        "429": "Teto de organizações novas da conta.",
        "503": "Origem, conta ou orçamento indisponível."
      },
      "exemplo": "curl -s -X PUT '$ORIGIN/api/me/empresas/00394460000141/selecionar' -H 'X-Api-Key: $CHAVE_DA_ORGANIZACAO'",
      "params": {
        "cnpj": {
          "desc": "CNPJ completo, 14 dígitos com verificação válida.",
          "exemplo": "00394460000141"
        }
      },
      "desc": "Escolha de cada pessoa, guardada na conta. Não executa análise; repetir a escolha atual não grava.",
      "returns": "{ itens[{cnpj,razao_social,nome_fantasia,situacao,situacao_desde,porte,natureza_juridica,inicio_atividade,matriz_filial,capital_social,municipio,uf,cnaes,fonte,importado_em,organizacao}], selecionada, selecionada_organizacao, limite, conta_necessaria }",
      "url": "https://editalmd.com/api/me/empresas/:cnpj/selecionar",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "DELETE",
      "path": "/api/me/empresas/:cnpj",
      "summary": "Tira a empresa da lista (dona ou administradora); organização e PDFs ficam, e adicionar o CNPJ a devolve.",
      "auth": "owner",
      "grupo": "Empresas",
      "retorno": "EmpresasConta",
      "erros": {
        "400": "CNPJ ou busca inválida.",
        "401": "Conta necessária (conta_necessaria) ou sessão encerrada; a busca aceita o convidado.",
        "403": "Origem recusada, chave da conta (organization_key_required), papel sem gestão (organization_role_required) ou compartilhada sem 2FA (organization_mfa_required).",
        "404": "Empresa ausente nas organizações de quem pede, ou CNPJ ausente na base.",
        "405": "Método não permitido.",
        "409": "Limite de 100 empresas, organização indicada que já tem empresa, ou organização da qual quem pede saiu.",
        "429": "Teto de organizações novas da conta.",
        "503": "Origem, conta ou orçamento indisponível."
      },
      "exemplo": "curl -s -X DELETE '$ORIGIN/api/me/empresas/00394460000141' -H 'X-Api-Key: $CHAVE_DA_ORGANIZACAO'",
      "params": {
        "cnpj": {
          "desc": "CNPJ completo, 14 dígitos com verificação válida.",
          "exemplo": "00394460000141"
        }
      },
      "returns": "{ itens[{cnpj,razao_social,nome_fantasia,situacao,situacao_desde,porte,natureza_juridica,inicio_atividade,matriz_filial,capital_social,municipio,uf,cnaes,fonte,importado_em,organizacao}], selecionada, selecionada_organizacao, limite, conta_necessaria }",
      "url": "https://editalmd.com/api/me/empresas/:cnpj",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "GET",
      "path": "/api/auth/bootstrap",
      "auth": "none",
      "grupo": "Conta",
      "summary": "Prepara o navegador para entrar na conta global.",
      "desc": "Define cookie HttpOnly restrito ao host. CSRF vinculado à sessão atual. Sem CORS.",
      "retorno": {
        "csrf": {
          "tipo": "string",
          "desc": "X-CSRF-Token"
        },
        "context": {
          "tipo": "string",
          "desc": "Opaque view context, also in X-MM-Context; not a credential / contexto opaco da vista, não é credencial."
        }
      },
      "erros": {
        "400": "invalid_request",
        "403": "invalid_origin / invalid_csrf",
        "503": "auth_unavailable: a sessão anterior é preservada / the previous session is preserved"
      },
      "returns": "{ csrf, context }",
      "url": "https://editalmd.com/api/auth/bootstrap",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/account/profile",
      "auth": "session",
      "grupo": "Conta",
      "exemplo": "await fetch(\"$ORIGIN/api/account/profile\", {credentials: \"same-origin\"}).then(r => r.json());",
      "exemploLinguagem": "js",
      "summary": "Consulta seu perfil global.",
      "desc": "Lê preferências atuais da conta. Altere-as na página da conta; produtos não mantêm perfil autoritativo separado.",
      "retorno": {
        "_texto": "{profile:{name,locale,timeZone,theme,revision}}"
      },
      "erros": {
        "401": "invalid_session",
        "503": "auth_unavailable"
      },
      "returns": "{profile:{name,locale,timeZone,theme,revision}}",
      "url": "https://editalmd.com/api/account/profile",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "GET",
      "path": "/api/account/avatar",
      "auth": "session",
      "grupo": "Conta",
      "exemplo": "await fetch(\"$ORIGIN/api/account/avatar\", {credentials: \"same-origin\"}).then(r => {if (!r.ok) throw new Error(\"HTTP \" + r.status); return r.blob();});",
      "exemploLinguagem": "js",
      "summary": "Consulta sua foto de perfil global.",
      "desc": "WebP privado de até 64 KiB, sem cache. Altere-o na conta. Não aceita ID de usuário ou URL de objeto.",
      "retorno": {
        "_texto": "image/webp; Cache-Control: no-store"
      },
      "erros": {
        "401": "invalid_session",
        "404": "not_found: no photo / sem foto",
        "503": "auth_unavailable"
      },
      "returns": "image/webp; Cache-Control: no-store",
      "url": "https://editalmd.com/api/account/avatar",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "POST",
      "path": "/api/auth/logout",
      "auth": "session",
      "grupo": "Conta",
      "exemplo": "// Execute no console da página do produto / Run in the product page console.\n(async () => {\n  const origin = \"$ORIGIN\";\n  const {csrf} = await fetch(origin + \"/api/auth/bootstrap\").then(r => r.json());\n  const r = await fetch(origin + \"/api/auth/logout\", {\n    method: \"POST\", credentials: \"same-origin\",\n    headers: {\"Content-Type\": \"application/json\", \"X-CSRF-Token\": csrf},\n    body: JSON.stringify({})\n  });\n  if (!r.ok) throw new Error(\"Auth HTTP \" + r.status);\n  return r.json();\n})();",
      "exemploLinguagem": "js",
      "summary": "Revoga esta sessão do produto.",
      "desc": "Exige bootstrap/CSRF deste navegador e sessão. As sessões de outros produtos permanecem ativas.",
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "true"
        }
      },
      "erros": {
        "400": "invalid_request",
        "403": "invalid_origin / invalid_csrf",
        "503": "auth_unavailable: a sessão anterior é preservada / the previous session is preserved"
      },
      "returns": "{ ok }",
      "url": "https://editalmd.com/api/auth/logout",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "POST",
      "path": "/api/auth/pwa/install",
      "auth": "session",
      "grupo": "App instalado",
      "summary": "Prepara uma instalação pessoal do app.",
      "desc": "Exige entrada recente, Origin exato e CSRF do navegador. Retorna PIN privado assinado e endereço do manifesto sem cache. Até 10 instalações ativas por conta e produto.",
      "corpo": {
        "path": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Same-origin task path, up to 1600 characters."
        },
        "state": {
          "tipo": "object",
          "obrigatorio": true,
          "desc": "Up to 30 allowlisted preference keys and string values."
        },
        "manifest": {
          "tipo": "object",
          "obrigatorio": true,
          "desc": "Public app name and same-origin icons."
        }
      },
      "retorno": {
        "_texto": "{pin,path,manifest}"
      },
      "exemplo": "(async () => {\n  const {csrf} = await fetch(\"$ORIGIN/api/auth/bootstrap\").then(r => r.json());\n  const manifest = await fetch(document.querySelector('link[rel=\"manifest\"]').href).then(r => r.json());\n  const r = await fetch(\"$ORIGIN/api/auth/pwa/install\", {method: \"POST\", credentials: \"same-origin\",\n    headers: {\"Content-Type\": \"application/json\", \"X-CSRF-Token\": csrf},\n    body: JSON.stringify({path: location.pathname + location.search, state: {}, manifest})});\n  return r.json();\n})();",
      "exemploLinguagem": "js",
      "erros": {
        "400": "invalid_installation_path / invalid_installation_state / invalid_installation_manifest",
        "401": "invalid_session / reauth_required",
        "409": "installation_not_created",
        "503": "auth_unavailable"
      },
      "returns": "{pin,path,manifest}",
      "url": "https://editalmd.com/api/auth/pwa/install",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "POST",
      "path": "/api/auth/pwa/restore",
      "auth": "none",
      "grupo": "App instalado",
      "summary": "Restaura um app instalado.",
      "desc": "Exige PIN assinado, Origin exato e CSRF do navegador. Confere host, produto, conta, versão de segurança e revogação da instalação. Mantém a hora da autenticação original. Ações sensíveis continuam exigindo entrada recente.",
      "corpo": {
        "pin": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Private signed installation credential."
        }
      },
      "retorno": {
        "_texto": "{ok:true,state,path,manifest}; HttpOnly session cookies"
      },
      "exemplo": "(async () => {\n  const {csrf} = await fetch(\"$ORIGIN/api/auth/bootstrap\").then(r => r.json());\n  const r = await fetch(\"$ORIGIN/api/auth/pwa/restore\", {method: \"POST\", credentials: \"same-origin\",\n    headers: {\"Content-Type\": \"application/json\", \"X-CSRF-Token\": csrf},\n    body: JSON.stringify({pin: \"…\"})});\n  return r.json();\n})();",
      "exemploLinguagem": "js",
      "erros": {
        "401": "invalid_installation",
        "403": "invalid_origin / invalid_csrf",
        "503": "auth_unavailable"
      },
      "returns": "{ok:true,state,path,manifest}; HttpOnly session cookies",
      "url": "https://editalmd.com/api/auth/pwa/restore",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/auth/pwa/manifest",
      "auth": "none",
      "grupo": "App instalado",
      "summary": "Consulta o manifesto privado da instalação.",
      "desc": "Exige cookie da instalação e chave do manifesto. Privado e sem cache. A URL inicial guarda o PIN no fragmento.",
      "query": {
        "key": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Key in the manifest address that the install or restore call returned."
        }
      },
      "retorno": {
        "_texto": "application/manifest+json"
      },
      "exemplo": "await fetch(\"$ORIGIN/api/auth/pwa/manifest?key=…\", {credentials: \"same-origin\"}).then(r => r.json())",
      "exemploLinguagem": "js",
      "erros": {
        "401": "invalid_installation"
      },
      "returns": "application/manifest+json",
      "url": "https://editalmd.com/api/auth/pwa/manifest",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/account/keys",
      "auth": "session",
      "grupo": "Conta",
      "summary": "Lista suas chaves de API neste produto.",
      "desc": "Nunca devolve a chave: nome, 4 últimos caracteres, organização, criação, último uso (por hora) e se ainda vale.",
      "retorno": {
        "keys": {
          "tipo": "object[]",
          "desc": "`id`, `name`, `organizationId`, `last4`, `createdAt`, `lastUsedAt`, `revokedAt`, `active` (false quando revogada ou parada por troca de senha / encerrar todos os acessos)."
        }
      },
      "erros": {
        "401": "invalid_session",
        "503": "auth_unavailable"
      },
      "exemplo": "await fetch(\"$ORIGIN/api/account/keys\", {credentials: \"same-origin\"}).then(r => r.json());",
      "exemploLinguagem": "js",
      "returns": "{ keys }",
      "url": "https://editalmd.com/api/account/keys",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "POST",
      "path": "/api/account/keys/create",
      "auth": "session",
      "grupo": "Conta",
      "summary": "Cria uma chave de API para agentes e scripts.",
      "desc": "Exige entrada feita há até 2 horas; a de organização também exige segundo fator na sessão e o papel de dona/administradora com o produto ligado. No máximo 10 chaves vivas por conta e produto. A chave (`secret`) volta UMA vez.",
      "corpo": {
        "name": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Até 60 caracteres."
        },
        "organizationId": {
          "tipo": "string",
          "nulo": true,
          "obrigatorio": true,
          "desc": "`null` para chave da conta."
        }
      },
      "body": {
        "name": "agent",
        "organizationId": null
      },
      "retorno": {
        "key": {
          "tipo": "object",
          "desc": "`id`, `name`, `organizationId`, `last4`, `createdAt`."
        },
        "secret": {
          "tipo": "string",
          "desc": "`mmk_…`, mostrada uma vez."
        }
      },
      "erros": {
        "400": "invalid_key_name / invalid_organization",
        "401": "invalid_session / reauth_required",
        "403": "invalid_origin / invalid_csrf / organization_forbidden / organization_mfa_required",
        "409": "key_limit_reached",
        "503": "auth_unavailable"
      },
      "exemplo": "(async () => {\n  const {csrf} = await fetch(\"$ORIGIN/api/auth/bootstrap\").then(r => r.json());\n  const r = await fetch(\"$ORIGIN/api/account/keys/create\", {method: \"POST\", credentials: \"same-origin\",\n    headers: {\"Content-Type\": \"application/json\", \"X-CSRF-Token\": csrf},\n    body: JSON.stringify({name: \"agent\", organizationId: null})});\n  return r.json();\n})();",
      "exemploLinguagem": "js",
      "returns": "{ key, secret }",
      "url": "https://editalmd.com/api/account/keys/create",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "POST",
      "path": "/api/account/keys/revoke",
      "auth": "session",
      "grupo": "Conta",
      "summary": "Revoga uma das suas chaves de API.",
      "desc": "Para a chave na hora. Repetir não faz mal.",
      "corpo": {
        "id": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "O `id` da chave."
        }
      },
      "body": {
        "id": "…"
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "true"
        }
      },
      "erros": {
        "400": "invalid_key_id",
        "401": "invalid_session",
        "403": "invalid_origin / invalid_csrf",
        "404": "key_not_found",
        "503": "auth_unavailable"
      },
      "exemplo": "(async () => {\n  const {csrf} = await fetch(\"$ORIGIN/api/auth/bootstrap\").then(r => r.json());\n  const r = await fetch(\"$ORIGIN/api/account/keys/revoke\", {method: \"POST\", credentials: \"same-origin\",\n    headers: {\"Content-Type\": \"application/json\", \"X-CSRF-Token\": csrf},\n    body: JSON.stringify({id: \"…\"})});\n  return r.json();\n})();",
      "exemploLinguagem": "js",
      "returns": "{ ok }",
      "url": "https://editalmd.com/api/account/keys/revoke",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "GET",
      "path": "/api/account/apps",
      "auth": "session",
      "grupo": "Conta",
      "summary": "Lista os apps conectados à sua conta neste produto.",
      "desc": "Os clientes de MCP em que você entrou com a conta (OAuth), como o claude.ai ou o ChatGPT. Nunca devolve token.",
      "retorno": {
        "apps": {
          "tipo": "object[]",
          "desc": "Até 50: `id`, `nome` (o app; o host dele quando ele se identifica por documento de metadados), `criadoEm`, `usadoEm` (por hora, ou null)."
        }
      },
      "erros": {
        "401": "invalid_session",
        "503": "auth_unavailable"
      },
      "exemplo": "await fetch(\"$ORIGIN/api/account/apps\", {credentials: \"same-origin\"}).then(r => r.json());",
      "exemploLinguagem": "js",
      "returns": "{ apps }",
      "url": "https://editalmd.com/api/account/apps",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "POST",
      "path": "/api/account/apps/revoke",
      "auth": "session",
      "grupo": "Conta",
      "summary": "Desconecta um app da sua conta.",
      "desc": "Para o acesso do app na hora; ele pede o login de novo. Repetir não faz mal.",
      "corpo": {
        "id": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "O `id` do app."
        }
      },
      "body": {
        "id": "…"
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "true"
        }
      },
      "erros": {
        "400": "invalid_app_id",
        "401": "invalid_session",
        "403": "invalid_origin / invalid_csrf",
        "404": "app_not_found",
        "503": "auth_unavailable"
      },
      "exemplo": "(async () => {\n  const {csrf} = await fetch(\"$ORIGIN/api/auth/bootstrap\").then(r => r.json());\n  const r = await fetch(\"$ORIGIN/api/account/apps/revoke\", {method: \"POST\", credentials: \"same-origin\",\n    headers: {\"Content-Type\": \"application/json\", \"X-CSRF-Token\": csrf},\n    body: JSON.stringify({id: \"…\"})});\n  return r.json();\n})();",
      "exemploLinguagem": "js",
      "returns": "{ ok }",
      "url": "https://editalmd.com/api/account/apps/revoke",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "GET",
      "path": "/api/account/callouts",
      "auth": "session",
      "grupo": "Conta",
      "summary": "Lista os avisos que você fechou neste produto.",
      "desc": "As chaves dos avisos que ficam fechados para a sua conta, em todo aparelho, como a explicação de uma área.",
      "retorno": {
        "callouts": {
          "tipo": "string[]",
          "desc": "Até 200 chaves, em ordem alfabética."
        }
      },
      "erros": {
        "401": "invalid_session",
        "403": "product_required",
        "503": "auth_unavailable"
      },
      "exemplo": "await fetch(\"$ORIGIN/api/account/callouts\", {credentials: \"same-origin\"}).then(r => r.json());",
      "exemploLinguagem": "js",
      "returns": "{ callouts }",
      "url": "https://editalmd.com/api/account/callouts",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "POST",
      "path": "/api/account/callouts/dismiss",
      "auth": "session",
      "grupo": "Conta",
      "summary": "Fecha um aviso de vez.",
      "desc": "O aviso não abre de novo para a sua conta neste produto. Repetir não faz mal.",
      "corpo": {
        "key": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "A chave do aviso: letras, números e `_.:-`, até 80."
        }
      },
      "body": {
        "key": "financeiro_expense"
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "true"
        }
      },
      "erros": {
        "400": "invalid_callout",
        "401": "invalid_session",
        "403": "invalid_origin / invalid_csrf",
        "409": "too_many_callouts",
        "503": "auth_unavailable"
      },
      "exemplo": "(async () => {\n  const {csrf} = await fetch(\"$ORIGIN/api/auth/bootstrap\").then(r => r.json());\n  const r = await fetch(\"$ORIGIN/api/account/callouts/dismiss\", {method: \"POST\", credentials: \"same-origin\",\n    headers: {\"Content-Type\": \"application/json\", \"X-CSRF-Token\": csrf},\n    body: JSON.stringify({key: \"financeiro_expense\"})});\n  return r.json();\n})();",
      "exemploLinguagem": "js",
      "returns": "{ ok }",
      "url": "https://editalmd.com/api/account/callouts/dismiss",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "POST",
      "path": "/api/account/callouts/reopen",
      "auth": "session",
      "grupo": "Conta",
      "summary": "Reabre um aviso fechado.",
      "desc": "Desfaz o fechar: o aviso volta para a sua conta neste produto. O produto guarda aqui também uma escolha de ligar e desligar, como os valores ocultos do Financeiro. Repetir não faz mal.",
      "corpo": {
        "key": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "A chave do aviso: letras, números e `_.:-`, até 80."
        }
      },
      "body": {
        "key": "financeiro_expense"
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "true"
        }
      },
      "erros": {
        "400": "invalid_callout",
        "401": "invalid_session",
        "403": "invalid_origin / invalid_csrf",
        "503": "auth_unavailable"
      },
      "exemplo": "(async () => {\n  const {csrf} = await fetch(\"$ORIGIN/api/auth/bootstrap\").then(r => r.json());\n  const r = await fetch(\"$ORIGIN/api/account/callouts/reopen\", {method: \"POST\", credentials: \"same-origin\",\n    headers: {\"Content-Type\": \"application/json\", \"X-CSRF-Token\": csrf},\n    body: JSON.stringify({key: \"financeiro_expense\"})});\n  return r.json();\n})();",
      "exemploLinguagem": "js",
      "returns": "{ ok }",
      "url": "https://editalmd.com/api/account/callouts/reopen",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "POST",
      "path": "/api/auth/wallet/agent/start",
      "auth": "none",
      "grupo": "Conta",
      "summary": "Começa a credencial de carteira do agente sem conta.",
      "desc": "Sem conta: a carteira prova que é dela assinando a mensagem (EIP-4361). Assinar não paga nem transfere nada. A mensagem diz este produto e vale 5 minutos. Antes de assinar, compare a mensagem com a URL chamada. O domínio da primeira linha deve ser o host dessa URL. O URI deve ser a origem dela. Se um deles for diferente, não assine. Assine com personal_sign e envie a /api/auth/wallet/agent/token.",
      "corpo": {
        "address": {
          "tipo": "string",
          "desc": "0x…, a carteira (EOA ou contrato na Base)",
          "obrigatorio": true
        }
      },
      "body": {
        "address": "0x2c7536E3605D9C16a7a3D7b1898e529396a65c23"
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/auth/wallet/agent/start -H 'content-type: application/json' -d '{\"address\":\"0x2c7536E3605D9C16a7a3D7b1898e529396a65c23\"}'",
      "retorno": {
        "message": {
          "tipo": "string",
          "desc": "EIP-4361"
        },
        "issuedAt": {
          "tipo": "number",
          "desc": "segundos / seconds"
        },
        "expiresIn": {
          "tipo": "number",
          "desc": "300"
        }
      },
      "erros": {
        "400": "invalid_wallet_address",
        "503": "auth_unavailable"
      },
      "returns": "{ message, issuedAt, expiresIn }",
      "url": "https://editalmd.com/api/auth/wallet/agent/start",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/auth/wallet/agent/token",
      "auth": "none",
      "grupo": "Conta",
      "summary": "Recebe a credencial da carteira (mmw_…) deste produto.",
      "desc": "A assinatura da carteira na mensagem do start, conferida aqui (chave própria) ou na Base (contrato, EIP-1271/6492). A credencial vale 30 dias: envie `Authorization: Bearer mmw_…` às rotas que aceitam a carteira como dona (dono `x402:<endereço>`). Vinculada a carteira a uma conta, o que ela fez aqui passa para a conta quando a pessoa entra.",
      "corpo": {
        "address": {
          "tipo": "string",
          "desc": "0x…, a mesma carteira do start / the same wallet as in start",
          "obrigatorio": true
        },
        "issuedAt": {
          "tipo": "number",
          "desc": "o issuedAt do start / start's issuedAt",
          "obrigatorio": true
        },
        "signature": {
          "tipo": "string",
          "desc": "personal_sign (0x…)",
          "obrigatorio": true
        }
      },
      "body": {
        "address": "0x2c7536E3605D9C16a7a3D7b1898e529396a65c23",
        "issuedAt": 1791400000,
        "signature": "0x…"
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/auth/wallet/agent/token -H 'content-type: application/json' -d '{\"address\":\"0x2c7536E3605D9C16a7a3D7b1898e529396a65c23\",\"issuedAt\":1791400000,\"signature\":\"0x…\"}'",
      "retorno": {
        "token": {
          "tipo": "string",
          "desc": "mmw_…"
        },
        "owner": {
          "tipo": "string",
          "desc": "x402:0x…"
        },
        "expiresAt": {
          "tipo": "number",
          "desc": "segundos / seconds"
        }
      },
      "erros": {
        "400": "invalid_body",
        "401": "invalid_wallet",
        "429": "wallet_limited",
        "503": "wallet_unavailable / auth_unavailable"
      },
      "returns": "{ token, owner, expiresAt }",
      "url": "https://editalmd.com/api/auth/wallet/agent/token",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/auth/claim/wallets",
      "auth": "session",
      "grupo": "Conta",
      "summary": "Passa para a conta o que as carteiras dela fizeram sem conta.",
      "desc": "A janela de entrar chama depois de toda entrada. Para cada carteira vinculada à conta: os direitos comprados aqui por x402 (dono x402:<endereço>) e o que este produto guarda desse dono. Repetir não move nada.",
      "exemplo": "await MMConta.fetch(new URL(\"$ORIGIN/api/auth/claim/wallets\").pathname, { method: \"POST\", headers: { \"content-type\": \"application/json\" }, body: \"{}\" })",
      "retorno": {
        "carteiras": {
          "tipo": "number",
          "desc": "wallets"
        },
        "direitos": {
          "tipo": "number",
          "desc": "rights moved"
        }
      },
      "erros": {
        "401": "invalid_session",
        "503": "auth_unavailable"
      },
      "returns": "{ carteiras, direitos }",
      "url": "https://editalmd.com/api/auth/claim/wallets",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "POST",
      "path": "/api/auth/claim",
      "auth": "session",
      "grupo": "Conta",
      "summary": "Passa para a conta o que o convidado criou: as Salvas, os Alertas e as Vigias que a conta ainda não tem (uma lista de cada por conta), o segredo do webhook se ela ainda não tem um, e as compras do convidado.",
      "desc": "Exige bootstrap/CSRF deste navegador; a página faz isso logo depois de entrar. Só passa o que o convidado ainda tem, numa transação, e o que colide com o que a conta já tem fica com o convidado. O que o convidado comprou passa junto. Token antigo, sem assinatura, que não é dono de nada aqui é recusado. Repetir não faz mal (move zero).",
      "corpo": {
        "guest_token": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Convidado `edm_…` deste navegador."
        }
      },
      "body": {
        "guest_token": "edm_…"
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Se o convidado foi reconhecido e passou."
        },
        "claimed": {
          "tipo": "object",
          "desc": "`product.movidos` (linhas que mudaram de dono, por tabela), `product.apagados` (duplicatas do convidado descartadas) e `product.direitos` (compras que passaram)."
        }
      },
      "erros": {
        "400": "invalid_product_claim / invalid_body",
        "401": "invalid_session",
        "403": "invalid_origin / invalid_csrf",
        "409": "unknown_guest (em `claimed.reason` / in `claimed.reason`)",
        "503": "product_claim_pending / auth_unavailable"
      },
      "exemplo": "(async () => {\n  const {csrf} = await fetch(\"$ORIGIN/api/auth/bootstrap\").then(r => r.json());\n  const r = await fetch(\"$ORIGIN/api/auth/claim\", {method: \"POST\", credentials: \"same-origin\",\n    headers: {\"Content-Type\": \"application/json\", \"X-CSRF-Token\": csrf},\n    body: JSON.stringify({guest_token: localStorage.getItem(\"editalmd_token\")})});\n  return r.json();\n})();",
      "exemploLinguagem": "js",
      "returns": "{ ok, claimed }",
      "url": "https://editalmd.com/api/auth/claim",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "GET",
      "path": "/api/me",
      "summary": "Identifica sua conta, conta seus acessos e acompanhamentos e aponta biblioteca e histórico.",
      "retorno": {
        "user": {
          "tipo": "object",
          "desc": "id (o id da conta global) e email da conta."
        },
        "documentos_url": {
          "tipo": "string",
          "desc": "Biblioteca privada."
        },
        "compras_url": {
          "tipo": "string",
          "desc": "Histórico privado."
        },
        "totais": {
          "tipo": "object",
          "desc": "documentos (IDs distintos com direito comprado), salvas e alertas (incluindo pausados) da conta; zero quando vazio."
        },
        "acompanhamento_vinculado": {
          "tipo": "bool",
          "desc": "Sempre true: a conta é dona direto das listas dela."
        },
        "locais_vinculados": {
          "tipo": "int[]",
          "desc": "Dos IDs informados em locais, somente os que já pertencem à conta atual; evita duplicar o contador do navegador. Não concede acesso."
        }
      },
      "grupo": "Conta",
      "auth": "session",
      "erros": {
        "400": "Corpo/cursor inválido.",
        "401": "Sessão ausente, inválida ou encerrada (`session_ended`: entre de novo).",
        "403": "Origem de mutação ou CSRF recusados.",
        "404": "Aquisição não encontrada para este cliente.",
        "405": "Método não permitido.",
        "503": "Conta ou limite global indisponível."
      },
      "exemplo": "await fetch(\"$ORIGIN/api/me\", {credentials: \"same-origin\"}).then(r => r.json());",
      "exemploLinguagem": "js",
      "desc": "A conta global já é a pessoa no EditalMD: não há ativação por produto.",
      "query": {
        "locais": {
          "tipo": "string",
          "desc": "Até 90 IDs positivos de documentos separados por vírgula, no máximo 1529 caracteres; omita se não houver acessos locais para conciliar."
        }
      },
      "returns": "{ user, documentos_url, compras_url, totais, acompanhamento_vinculado, locais_vinculados }",
      "url": "https://editalmd.com/api/me",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "GET",
      "path": "/api/me/documentos",
      "summary": "Documentos comprados por esta conta; reabertura sem novo pagamento.",
      "retorno": {
        "itens": {
          "tipo": "object[]",
          "desc": "Direitos de documento da conta (direito global do pagamento): id, documento_id, via (x402, credito, deposito, franquia do plano ou simulado, o pagamento de teste), created_at, abrir_url, geracao_url, markdown_url."
        },
        "proximo_antes": {
          "tipo": "string",
          "desc": "Sempre null: a coleção vem inteira, até 200.",
          "nulo": true
        }
      },
      "grupo": "Conta",
      "auth": "session",
      "erros": {
        "400": "Corpo/cursor inválido.",
        "401": "Sessão ausente, inválida ou encerrada (`session_ended`: entre de novo).",
        "403": "Origem de mutação ou CSRF recusados.",
        "404": "Aquisição não encontrada para este cliente.",
        "405": "Método não permitido.",
        "503": "Conta ou limite global indisponível."
      },
      "exemplo": "await fetch(\"$ORIGIN/api/me/documentos\", {credentials: \"same-origin\"}).then(r => r.json());",
      "exemploLinguagem": "js",
      "query": {
        "antes": {
          "tipo": "string",
          "desc": "proximo_antes da página anterior; hex, cursor exclusivo do cliente."
        }
      },
      "colecao": {
        "porPagina": 200,
        "teto": 200,
        "anda": "Tudo vem na primeira página; proximo_antes é sempre null."
      },
      "returns": "{ itens, proximo_antes }",
      "url": "https://editalmd.com/api/me/documentos",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "GET",
      "path": "/api/me/compras",
      "summary": "Histórico privado das aquisições, mais recentes primeiro.",
      "retorno": {
        "itens": {
          "tipo": "object[]",
          "desc": "Direitos de documento da conta (direito global do pagamento): id, documento_id, via (x402, credito, deposito, franquia do plano ou simulado, o pagamento de teste), created_at, abrir_url, geracao_url, markdown_url."
        },
        "proximo_antes": {
          "tipo": "string",
          "desc": "Sempre null: a coleção vem inteira, até 200.",
          "nulo": true
        }
      },
      "grupo": "Conta",
      "auth": "session",
      "erros": {
        "400": "Corpo/cursor inválido.",
        "401": "Sessão ausente, inválida ou encerrada (`session_ended`: entre de novo).",
        "403": "Origem de mutação ou CSRF recusados.",
        "404": "Aquisição não encontrada para este cliente.",
        "405": "Método não permitido.",
        "503": "Conta ou limite global indisponível."
      },
      "exemplo": "await fetch(\"$ORIGIN/api/me/compras\", {credentials: \"same-origin\"}).then(r => r.json());",
      "exemploLinguagem": "js",
      "query": {
        "antes": {
          "tipo": "string",
          "desc": "proximo_antes da página anterior; hex, cursor exclusivo do cliente."
        }
      },
      "colecao": {
        "porPagina": 200,
        "teto": 200,
        "anda": "Tudo vem na primeira página; proximo_antes é sempre null."
      },
      "returns": "{ itens, proximo_antes }",
      "url": "https://editalmd.com/api/me/compras",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "POST",
      "path": "/api/documento/:id/vincular",
      "summary": "Associa sua aquisição anônima à conta autenticada, sem nova cobrança.",
      "retorno": {
        "vinculado": {
          "tipo": "bool",
          "desc": "Aquisição pertence à conta."
        },
        "documento_id": {
          "tipo": "int",
          "desc": "Documento."
        }
      },
      "grupo": "Conta",
      "auth": "session",
      "erros": {
        "400": "Corpo/cursor inválido.",
        "401": "Sessão ausente, inválida ou encerrada (`session_ended`: entre de novo).",
        "403": "Origem de mutação ou CSRF recusados.",
        "404": "Aquisição não encontrada para este cliente.",
        "405": "Método não permitido.",
        "503": "Conta ou limite global indisponível."
      },
      "exemplo": "(async () => {\n  const {csrf} = await fetch(\"$ORIGIN/api/auth/bootstrap\").then(r => r.json());\n  const r = await fetch(\"$ORIGIN/api/documento/2110258/vincular\", {method: \"POST\", credentials: \"same-origin\",\n    headers: {\"X-CSRF-Token\": csrf, \"X-Editalmd-Acesso\": ACESSO}});\n  return r.json();\n})();",
      "exemploLinguagem": "js",
      "params": {
        "id": {
          "desc": "ID positivo do documento comprado."
        }
      },
      "headers": {
        "X-Editalmd-Acesso": {
          "tipo": "string",
          "desc": "Capacidade privada recebida após pagamento. Cookie documental também aceito."
        }
      },
      "desc": "Exige sessão e prova privada da aquisição. Grava o direito global da conta pelo recibo do pagamento: idempotente para o mesmo dono, e outro dono não pode reivindicar. O código continua abrindo o documento sozinho.",
      "returns": "{ vinculado, documento_id }",
      "url": "https://editalmd.com/api/documento/:id/vincular",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "GET",
      "path": "/api/documento/:id/acesso",
      "summary": "Confere vínculo e permite exportar o código da aquisição ainda anônima.",
      "retorno": {
        "documento_id": {
          "tipo": "int",
          "desc": "Documento."
        },
        "vinculado": {
          "tipo": "bool",
          "desc": "A conta atual possui este documento."
        },
        "recuperacao": {
          "tipo": "string",
          "desc": "Código privado exportável somente enquanto não vinculado.",
          "nulo": true
        }
      },
      "grupo": "Conta",
      "auth": "acesso",
      "erros": {
        "400": "Corpo/cursor inválido.",
        "401": "Sessão ausente, inválida ou encerrada (`session_ended`: entre de novo).",
        "402": "Acesso não comprado.",
        "403": "Origem de mutação ou CSRF recusados.",
        "404": "Aquisição não encontrada para este cliente.",
        "405": "Método não permitido.",
        "503": "Conta ou limite global indisponível."
      },
      "exemplo": "await fetch(\"$ORIGIN/api/documento/2110258/acesso\", {credentials: \"same-origin\"}).then(r => r.json());",
      "exemploLinguagem": "js",
      "params": {
        "id": {
          "desc": "ID positivo do documento comprado."
        }
      },
      "headers": {
        "X-Editalmd-Acesso": {
          "tipo": "string",
          "desc": "Código de acesso; sessão/cookie equivalente aceitos."
        }
      },
      "returns": "{ documento_id, vinculado, recuperacao }",
      "url": "https://editalmd.com/api/documento/:id/acesso",
      "auth_detail": "Sessão da conta com aquisição vinculada, X-Editalmd-Acesso de compra anônima, ou X-Editalmd-Avaliacao junto de X-Agent-Pass para o documento patrocinado. Depois do vínculo da compra, exige conta. Os exemplos são livres."
    },
    {
      "method": "GET",
      "path": "/api/me/acompanhamento",
      "summary": "Confere que Salvas/Alertas/Vigias são da conta da sessão.",
      "retorno": {
        "vinculado": {
          "tipo": "bool",
          "desc": "Sempre true com sessão: a conta é dona direto das listas dela."
        }
      },
      "grupo": "Conta",
      "auth": "session",
      "erros": {
        "400": "Corpo/cursor inválido.",
        "401": "Sessão ausente, inválida ou encerrada (`session_ended`: entre de novo).",
        "403": "Origem de mutação ou CSRF recusados.",
        "404": "Aquisição não encontrada para este cliente.",
        "405": "Método não permitido.",
        "503": "Conta ou limite global indisponível."
      },
      "exemplo": "await fetch(\"$ORIGIN/api/me/acompanhamento\", {credentials: \"same-origin\"}).then(r => r.json());",
      "exemploLinguagem": "js",
      "desc": "As listas de um convidado edm_… passam para a conta em `POST /api/auth/claim`; o POST desta rota responde 410 com o caminho.",
      "returns": "{ vinculado }",
      "url": "https://editalmd.com/api/me/acompanhamento",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "GET",
      "path": "/api/",
      "auth": "none",
      "summary": "Índice auto-descrito: rotas, regime de cobrança, preço e MCP.",
      "grupo": "Descoberta",
      "retorno": {
        "name": {
          "tipo": "string",
          "desc": "Nome do produto."
        },
        "description": {
          "tipo": "string",
          "desc": "O que o produto faz."
        },
        "build": {
          "tipo": "string",
          "desc": "Commit publicado."
        },
        "base_url": {
          "tipo": "string",
          "desc": "Origem em que esta API está servindo."
        },
        "docs": {
          "tipo": "object",
          "desc": "Links para llms.txt, OpenAPI, MCP e a UI."
        },
        "endpoints": {
          "tipo": "object[]",
          "desc": "Catálogo de endpoints."
        },
        "mcp_tools": {
          "tipo": "string[]",
          "desc": "Tools do MCP."
        },
        "regime": {
          "tipo": "string",
          "desc": "A regra de cobrança por recência, em uma frase."
        },
        "gratis_acima_de_dias": {
          "tipo": "int",
          "desc": "Idade de publicação a partir da qual o documento é amostra grátis."
        },
        "pago": {
          "tipo": "object",
          "desc": "Rota paga e o preço por requisição."
        },
        "cota": {
          "tipo": "object",
          "desc": "O que é grátis, o que é pago e como pagar."
        }
      },
      "exemplo": "curl -s $ORIGIN/api/",
      "returns": "{ name, description, build, base_url, docs, endpoints, mcp_tools, regime, gratis_acima_de_dias, pago, cota }",
      "url": "https://editalmd.com/api/",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/health",
      "auth": "none",
      "grupo": "Descoberta",
      "summary": "Saúde da origem e tamanho do acervo.",
      "retorno": "Saude",
      "erros": {
        "503": "Origem indisponível."
      },
      "exemplo": "curl -s $ORIGIN/api/health",
      "returns": "{ ok, build, acervo{compras,documentos_lidos}, preco_markdown_usd, gratis_acima_de_dias }",
      "url": "https://editalmd.com/api/health",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/mcp",
      "auth": "none",
      "summary": "MCP Streamable HTTP — as tools deste catálogo, despachadas neste mesmo Worker.",
      "grupo": "Descoberta",
      "retorno": {
        "_texto": "JSON-RPC 2.0 (`initialize`, `tools/list`, `tools/call`)."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/mcp -H 'content-type: application/json' -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/list\"}'",
      "returns": "JSON-RPC 2.0 (`initialize`, `tools/list`, `tools/call`).",
      "url": "https://editalmd.com/mcp",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/okf/:arquivo",
      "auth": "acesso",
      "summary": "Bundle OKF (Open Knowledge Format v0.1): markdown com frontmatter para o agente ler o produto inteiro sem parsear HTML.",
      "grupo": "Descoberta",
      "params": {
        "arquivo": {
          "desc": "`index.md`, `sobre.md`, `api.md` ou `faq.md`.",
          "exemplo": "index.md"
        }
      },
      "retorno": {
        "_texto": "`text/markdown`. Comece por `/okf/index.md`, que lista o bundle."
      },
      "erros": {
        "402": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; os exemplos são gratuitos.",
        "404": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente."
      },
      "exemplo": "curl -s $ORIGIN/okf/index.md",
      "headers": {
        "X-Agent-Pass": {
          "tipo": "string",
          "desc": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
        },
        "X-Editalmd-Avaliacao": {
          "tipo": "string",
          "desc": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
        },
        "X-Editalmd-Acesso": {
          "tipo": "string",
          "desc": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
        }
      },
      "returns": "`text/markdown`. Comece por `/okf/index.md`, que lista o bundle.",
      "url": "https://editalmd.com/okf/:arquivo",
      "auth_detail": "Sessão da conta com aquisição vinculada, X-Editalmd-Acesso de compra anônima, ou X-Editalmd-Avaliacao junto de X-Agent-Pass para o documento patrocinado. Depois do vínculo da compra, exige conta. Os exemplos são livres."
    },
    {
      "method": "GET",
      "path": "/.well-known/:arquivo",
      "auth": "none",
      "summary": "Descoberta de máquina antes da home: `api-catalog` (RFC 9727, linkset com a API e o MCP), `security.txt` (RFC 9116), `x402` (manifesto de pagamento: rede, carteira e rotas que cobram), `agent-card.json` (identidade do agente: ferramentas MCP e portas de descoberta; também em `/agent.json`) e `mcp-registry-auth` (chave do registro oficial de MCP).",
      "grupo": "Descoberta",
      "params": {
        "arquivo": {
          "desc": "`api-catalog`, `security.txt`, `x402`, `agent-card.json`, `mcp-registry-auth` ou `apis.json`.",
          "exemplo": "api-catalog"
        }
      },
      "retorno": {
        "_texto": "`application/linkset+json` no api-catalog; `application/json` no x402, no agent-card.json e no apis.json; `text/plain` nos outros dois."
      },
      "erros": {
        "404": "Nome fora dos seis publicados."
      },
      "exemplo": "curl -s $ORIGIN/.well-known/api-catalog",
      "returns": "`application/linkset+json` no api-catalog; `application/json` no x402, no agent-card.json e no apis.json; `text/plain` nos outros dois.",
      "url": "https://editalmd.com/.well-known/:arquivo",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/apis.json",
      "auth": "none",
      "summary": "APIs.json (apisjson.org, 0.19): o índice que o APIs.io colhe — a API, o MCP, OpenAPI, guia e bundle OKF num arquivo só. Também em `/.well-known/apis.json`.",
      "grupo": "Descoberta",
      "retorno": {
        "_texto": "`application/json` no formato APIs.json 0.19: `apis[]` com `baseURL`, `humanURL` e `properties[]`."
      },
      "exemplo": "curl -s $ORIGIN/apis.json",
      "returns": "`application/json` no formato APIs.json 0.19: `apis[]` com `baseURL`, `humanURL` e `properties[]`.",
      "url": "https://editalmd.com/apis.json",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/agent.json",
      "auth": "none",
      "summary": "Cartão do agente: identidade, quem opera, documentação, o endpoint MCP e as ferramentas que ele serve. Mesmo documento de `/.well-known/agent-card.json`.",
      "grupo": "Descoberta",
      "retorno": {
        "_texto": "`application/json`: `name`, `provider`, `protocol` (`mcp`), `interfaces[]` e `skills[]`."
      },
      "exemplo": "curl -s $ORIGIN/agent.json",
      "returns": "`application/json`: `name`, `provider`, `protocol` (`mcp`), `interfaces[]` e `skills[]`.",
      "url": "https://editalmd.com/agent.json",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/okf/:tipo/:id.md",
      "auth": "acesso",
      "summary": "O mesmo registro que a API responde, em markdown OKF: `documento` (Documento do acervo). Via de acesso para quem já tem o id, não catálogo.",
      "grupo": "Descoberta",
      "params": {
        "tipo": {
          "desc": "Um de: `documento`.",
          "exemplo": "documento"
        },
        "id": {
          "desc": "O id do registro, como a API o aceita.",
          "exemplo": "123"
        }
      },
      "retorno": {
        "_texto": "`text/markdown` com frontmatter OKF; `resource` aponta o JSON equivalente. Sem `.md` responde 301 para o canônico."
      },
      "erros": {
        "402": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; os exemplos são gratuitos.",
        "404": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente."
      },
      "exemplo": "curl -s $ORIGIN/okf/documento/123.md",
      "headers": {
        "X-Agent-Pass": {
          "tipo": "string",
          "desc": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
        },
        "X-Editalmd-Avaliacao": {
          "tipo": "string",
          "desc": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
        },
        "X-Editalmd-Acesso": {
          "tipo": "string",
          "desc": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
        }
      },
      "returns": "`text/markdown` com frontmatter OKF; `resource` aponta o JSON equivalente. Sem `.md` responde 301 para o canônico.",
      "url": "https://editalmd.com/okf/:tipo/:id.md",
      "auth_detail": "Sessão da conta com aquisição vinculada, X-Editalmd-Acesso de compra anônima, ou X-Editalmd-Avaliacao junto de X-Agent-Pass para o documento patrocinado. Depois do vínculo da compra, exige conta. Os exemplos são livres."
    },
    {
      "method": "GET",
      "path": "/feed.xml",
      "auth": "none",
      "summary": "RSS 2.0 das compras publicadas mais recentemente no acervo.",
      "grupo": "Descoberta",
      "retorno": {
        "_texto": "`application/rss+xml`."
      },
      "exemplo": "curl -s $ORIGIN/feed.xml",
      "returns": "`application/rss+xml`.",
      "url": "https://editalmd.com/feed.xml",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/feed.json",
      "auth": "none",
      "summary": "JSON Feed 1.1 das compras publicadas mais recentemente — o mesmo stream do RSS.",
      "grupo": "Descoberta",
      "retorno": {
        "_texto": "`application/feed+json`."
      },
      "exemplo": "curl -s $ORIGIN/feed.json",
      "returns": "`application/feed+json`.",
      "url": "https://editalmd.com/feed.json",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/busca",
      "auth": "none",
      "summary": "Busca compras públicas por termo. Consulta grátis.",
      "grupo": "Acervo",
      "query": {
        "q": {
          "tipo": "string",
          "desc": "Termo de busca; mínimo 3 letras. Espaço exige todas as palavras; `|` aceita alternativas no grupo. A sigla `CPSI` busca também “solução inovadora”, “soluções inovadoras”, “marco legal das startups” e “complementar nº 182”. Sem compra com todas as palavras, a busca traz as que têm parte delas, as com mais palavras primeiro, com `todas_as_palavras: false`.",
          "obrigatorio": true
        },
        "uf": {
          "tipo": "string",
          "desc": "Filtra por sigla de UF."
        },
        "abertas": {
          "tipo": "string",
          "desc": "`1` devolve só compras com prazo de proposta ainda por vencer. A revogada e a anulada no PNCP saem; a suspensa fica, com a situação.",
          "valores": [
            "1"
          ]
        },
        "ordem": {
          "tipo": "string",
          "desc": "`prazo` põe primeiro a compra cujo prazo de proposta encerra antes; a suspensa vem depois das que recebem proposta. Só com `abertas=1`.",
          "valores": [
            "prazo"
          ]
        },
        "limite": {
          "tipo": "int",
          "desc": "1 a 50 (padrão 20)."
        },
        "filtros": {
          "tipo": "string",
          "desc": "Objeto JSON, até 2048 caracteres: `excluir` e `municipios` (até 10 expressões de 3 a 80 caracteres; municípios por nome exato ou IBGE), `orgao_cnpj` (CNPJ exato, 14 dígitos), `modalidades` (até 10 códigos PNCP de 1 a 19), `disputa` (true: só compras com disputa de lances; com a modalidade 8, a dispensa com disputa), `srp` (true: só compras pelo Sistema de Registro de Preços), `esferas` (`F`, `E`, `D`, `M`: órgão federal, estadual, distrital ou municipal), `valor_min` e `valor_max` (reais, de 0 a 1e15; mínimo não supera máximo), `encerramento_de` e `encerramento_ate` (fim da proposta) e `publicacao_de` e `publicacao_ate` (publicação no PNCP), no dia `AAAA-MM-DD` de Brasília, com os dois dias incluídos; o início não passa do fim. Combine nomes de municípios com a UF para evitar homônimos. Exclusões são literais no objeto e nas informações complementares. Valor não informado no PNCP fica fora do filtro de valor. Ex.: {\"excluir\":[\"usado\"],\"modalidades\":[6],\"valor_min\":1000}."
        }
      },
      "retorno": "Busca",
      "erros": {
        "400": "Termo com menos de 3 letras, `filtros_invalidos`, `ordem_invalida` ou `ordem_exige_abertas`.",
        "502": "Origem indisponível.",
        "503": "Busca demorada: `busca_demorada`, com `Retry-After`; refine os termos. `filtros_indisponiveis` ou `ordem_indisponivel` quando a origem não confirma os filtros ou a ordem pedidos."
      },
      "exemplo": "curl -s '$ORIGIN/api/busca?q=uniforme%20escolar&uf=GO'",
      "returns": "{ itens[{id,pncp,objeto,uf,modalidade,situacao,orgao,unidade,valor_estimado,publicado_em,informacao_complementar,processo,abertura_proposta,encerramento_proposta,amparo_legal,amparo_legal_codigo,modalidade_id,situacao_id,municipio,municipio_ibge,orgao_cnpj,ano_compra,sequencial_compra,atualizado_em,prazos,pncp_url,markdown_url,compra_url,resultado?}], todas_as_palavras, preco_markdown_usd, gratis_acima_de_dias, pago, filtros?{excluir?,modalidades?,municipios?,orgao_cnpj?,valor_min?,valor_max?}, ordem? }",
      "url": "https://editalmd.com/api/busca",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/cnaes",
      "auth": "none",
      "summary": "Atividades econômicas (CNAE), descrições e sugestões de termos para alertas. Grátis.",
      "grupo": "Acervo",
      "desc": "Sem `q`, lista atividades com mais fornecedores registrados. Com `q`, busca por prefixo do código (`1412`, `1412-6/01`) ou por palavra da descrição. `familia`/`termos` nulos dizem que o CNAE ainda não está no dicionário: um alerta por CNPJ não o usa.",
      "query": {
        "q": {
          "tipo": "string",
          "desc": "Prefixo do código (2 a 7 dígitos) ou palavra da descrição (2+ letras)."
        },
        "limite": {
          "tipo": "int",
          "desc": "1 a 100 (padrão 20), por fornecedores no SICAF, decrescente."
        }
      },
      "retorno": {
        "itens": {
          "tipo": "Cnae[]",
          "desc": "Os CNAEs que casam, os com mais fornecedores primeiro."
        },
        "limite": {
          "tipo": "int",
          "desc": "Teto aplicado."
        },
        "q": {
          "tipo": "string",
          "desc": "O filtro aplicado.",
          "nulo": true
        },
        "dicionario": {
          "tipo": "object",
          "desc": "`familias`, `cnaes_mapeados` e `medido_em` (quando a cobertura no acervo foi medida)."
        },
        "fontes": {
          "tipo": "object",
          "desc": "Créditos dos dados apresentados."
        }
      },
      "erros": {
        "400": "`q` com menos de 2 caracteres.",
        "503": "Banco indisponível."
      },
      "exemplo": "curl -s '$ORIGIN/api/cnaes?q=1412'",
      "returns": "{ itens[{codigo,cnae,descricao,familia,familia_nome,termos,fornecedores_sicaf,sicaf_medido_em,ibge_atualizado_em}], limite, q, dicionario, fontes }",
      "url": "https://editalmd.com/api/cnaes",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/compra/:id",
      "auth": "none",
      "summary": "Ficha da compra com prazos de proposta e impugnação, documentos e o regime de cobrança de cada um.",
      "grupo": "Acervo",
      "desc": "Servida do cache da borda por até 6 horas: a ficha raramente muda. Os prazos e o preço de cada documento são calculados a cada pedido. `Cache-Control: no-cache` no pedido lê a origem na hora. O cabeçalho `x-origem-cache` diz `hit`, `miss` ou `bypass`.",
      "params": {
        "id": {
          "desc": "Identificador da compra, vindo da busca.",
          "exemplo": "42"
        }
      },
      "retorno": "FichaCompra",
      "erros": {
        "404": "Compra não encontrada.",
        "502": "Origem indisponível."
      },
      "exemplo": "curl -s $ORIGIN/api/compra/42",
      "returns": "{ compra{id,pncp,objeto,uf,modalidade,situacao,orgao,unidade,valor_estimado,publicado_em,informacao_complementar,processo,abertura_proposta,encerramento_proposta,amparo_legal,amparo_legal_codigo,modalidade_id,situacao_id,municipio,municipio_ibge,orgao_cnpj,ano_compra,sequencial_compra,atualizado_em,prazos,pncp_url,markdown_url,compra_url,resultado?}, documentos[{id,titulo,tipo,sequencial,publicado_em,caracteres,paginas,motor,formato,sha256,extraido_em,original_pendente,gratuito,preco_usd,markdown_url,geracao_url,preco_pagina_usd,disponivel}], regime{gratuito,motivo,idade_dias}, prazos{proposta_inicio,proposta_ate,proposta_aberta,impugnacao_ate,impugnacao_aberta,estimado,base_legal,feriados,motivo}, atas?[{ata,compra,atas,compra_id?,numero,orgao,orgao_cnpj,unidade,objeto,vigencia_inicio,vigencia_fim,adesao,pncp_url}] }",
      "url": "https://editalmd.com/api/compra/:id",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/compra/:id/cnaes",
      "auth": "none",
      "summary": "Quem fornece: os CNAEs que costumam vencer compras como esta. Grátis.",
      "grupo": "Acervo",
      "desc": "Cada item da compra (até 99, os de maior valor) aponta os 3 CNAEs mais prováveis, por um classificador treinado com a atividade de quem venceu itens parecidos nos resultados homologados do PNCP; a compra soma os pontos (3, 2 e 1 pela posição). Sem itens no acervo, vale o objeto da compra, e saem os 5 mais prováveis sem `itens` nem `valor_estimado`. Na medida de 27/09/2026, em 87% dos itens um dos 3 primeiros era CNAE da empresa que venceu. Para receber as novas compras desses CNAEs, crie um alerta (`POST /api/alertas`).",
      "params": {
        "id": {
          "desc": "Identificador da compra, vindo da busca.",
          "exemplo": "42"
        }
      },
      "retorno": {
        "compra_id": {
          "tipo": "int",
          "desc": "A compra."
        },
        "base": {
          "tipo": "string",
          "desc": "`itens` (pelo texto dos itens) ou `objeto` (a compra ainda não tem itens no acervo)."
        },
        "itens_considerados": {
          "tipo": "int",
          "desc": "Quantos itens entraram na conta (até 99)."
        },
        "cnaes": {
          "tipo": "object[]",
          "desc": "Até 8, do mais provável ao menos: `codigo` (7 dígitos), `cnae` (`4644-3/01`), `descricao` (a oficial), `itens` (quantos itens apontaram para ele) e `valor_estimado` (a soma do valor estimado desses itens, em reais)."
        },
        "modelo": {
          "tipo": "object",
          "desc": "`treinado_em`, `dados_ate` e `exemplos` (resultados homologados do treino)."
        }
      },
      "erros": {
        "400": "Id inválido.",
        "404": "Compra não encontrada.",
        "503": "Classificador indisponível (`modelo_ausente`)."
      },
      "exemplo": "curl -s $ORIGIN/api/compra/42/cnaes",
      "returns": "{ compra_id, base, itens_considerados, cnaes, modelo }",
      "url": "https://editalmd.com/api/compra/:id/cnaes",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/compra/:id/abertas",
      "auth": "none",
      "summary": "Abertas do mesmo ramo: licitações com proposta aberta para quem fornece o mesmo que esta compra. Grátis.",
      "grupo": "Acervo",
      "desc": "As compras publicadas nos últimos 7 dias, com proposta ainda aberta, na UF da compra e nos 3 CNAEs que mais costumam vencer compras como ela (`GET /api/compra/:id/cnaes`); sem CNAE, pelos termos do objeto. É a mesma leitura da prévia do alerta (`POST /api/alertas/previa`), e `alerta` traz o corpo que cria esse alerta em `POST /api/alertas` (acrescente o `canal`). O resultado é do ramo e da UF, guardado por 30 minutos; com a casa ocupada ou a origem fora, `estado` diz isso e `itens` vem vazio. É o que a ficha de uma licitação encerrada mostra ao lado do campo do alerta grátis.",
      "params": {
        "id": {
          "desc": "Identificador da compra, vindo da busca.",
          "exemplo": "42"
        }
      },
      "retorno": {
        "compra_id": {
          "tipo": "int",
          "desc": "A compra."
        },
        "periodo_dias": {
          "tipo": "int",
          "desc": "A janela da publicação: 7 dias."
        },
        "estado": {
          "tipo": "string",
          "desc": "`pronto`, `sem_recorte` (a compra não tem CNAE nem termos), `ocupado` (tente em um minuto) ou `indisponivel`."
        },
        "base": {
          "tipo": "string",
          "desc": "`cnaes` ou `termos`: de onde saiu o recorte.",
          "nulo": true
        },
        "uf": {
          "tipo": "string",
          "desc": "A UF do recorte.",
          "nulo": true
        },
        "cnaes": {
          "tipo": "string[]",
          "desc": "Os CNAEs do recorte (7 dígitos), quando a base é `cnaes`."
        },
        "termos": {
          "tipo": "string",
          "desc": "Os termos do recorte, quando a base é `termos`.",
          "nulo": true
        },
        "total": {
          "tipo": "int",
          "desc": "Quantas abertas a amostra achou (até 99 compras da semana são olhadas): é um mínimo, não o total da semana."
        },
        "itens": {
          "tipo": "object[]",
          "desc": "Até 5, as de maior valor estimado primeiro: `id`, `objeto`, `orgao`, `municipio`, `uf`, `modalidade`, `valor_estimado`, `encerramento_proposta` e `url` (a ficha)."
        },
        "alerta": {
          "tipo": "object",
          "desc": "O corpo de `POST /api/alertas` que entrega este recorte: `termos` (quando há), `uf` e `filtros`.",
          "nulo": true
        }
      },
      "erros": {
        "404": "Compra não encontrada.",
        "502": "Origem indisponível."
      },
      "exemplo": "curl -s $ORIGIN/api/compra/42/abertas",
      "returns": "{ compra_id, periodo_dias, estado, base, uf, cnaes, termos, total, itens, alerta }",
      "url": "https://editalmd.com/api/compra/:id/abertas",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/documento/:id/preparo",
      "auth": "none",
      "grupo": "Acervo",
      "summary": "Consulta gratuita do arquivo original, sem pedir trabalho.",
      "desc": "Responde apenas o estado do arquivo. Não entrega conteúdo, concede acesso, confirma páginas ou inicia geração. Sem query. Resposta no-store.",
      "params": {
        "id": {
          "desc": "ID positivo do documento retornado pela compra.",
          "exemplo": "4806436"
        }
      },
      "retorno": {
        "data": {
          "tipo": "object",
          "desc": "document_id identifica o documento. status é queued, downloading, downloaded ou unavailable. requested indica prioridade já pedida. retry_after_s é 60 enquanto pendente e 0 ao terminar."
        }
      },
      "erros": {
        "202": "Original pendente ou em download. Retry-After: 60. Consulte o canal ou o GET após esse prazo.",
        "400": "ID, query ou corpo inválido. POST aceita corpo vazio ou apenas {}.",
        "404": "Documento não encontrado.",
        "409": "Original indisponível. Nenhuma compra ou geração foi iniciada.",
        "429": "Limite de pedidos. Respeite Retry-After.",
        "502": "Resposta da origem inválida.",
        "503": "Não foi possível consultar o original."
      },
      "exemplo": "curl -s $ORIGIN/api/documento/4806436/preparo",
      "returns": "{ data }",
      "url": "https://editalmd.com/api/documento/:id/preparo",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/documento/:id/preparo",
      "auth": "none",
      "grupo": "Acervo",
      "summary": "Baixa agora do PNCP um original pendente. Gratuito e idempotente.",
      "desc": "Use quando a pessoa abre o documento. Corpo vazio ou {} de até dois bytes. Um coletor livre baixa o original na hora e o estado passa a downloading; sem coletor livre, o pedido fica primeiro na fila. Não inicia OCR, compra ou cobrança. Após a chegada, consulte /geracao para conferir páginas, hash e preço antes de comprar.",
      "params": {
        "id": {
          "desc": "ID positivo do documento retornado pela compra.",
          "exemplo": "4806436"
        }
      },
      "retorno": {
        "data": {
          "tipo": "object",
          "desc": "document_id identifica o documento. status é queued, downloading, downloaded ou unavailable. requested indica prioridade já pedida. retry_after_s é 60 enquanto pendente e 0 ao terminar."
        }
      },
      "erros": {
        "202": "Original pendente ou em download. Retry-After: 60. Consulte o canal ou o GET após esse prazo.",
        "400": "ID, query ou corpo inválido. POST aceita corpo vazio ou apenas {}.",
        "403": "Pedido do navegador fora da mesma origem.",
        "404": "Documento não encontrado.",
        "408": "Prazo de leitura do corpo encerrado.",
        "409": "Original indisponível. Nenhuma compra ou geração foi iniciada.",
        "413": "Corpo excedeu dois bytes.",
        "415": "Corpo comprimido não aceito.",
        "429": "Limite de pedidos. Respeite Retry-After.",
        "502": "Resposta da origem inválida.",
        "503": "Não foi possível consultar o original."
      },
      "exemplo": "curl -s -X POST $ORIGIN/api/documento/4806436/preparo",
      "returns": "{ data }",
      "url": "https://editalmd.com/api/documento/:id/preparo",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/documento/:id/preparo/canal",
      "auth": "none",
      "grupo": "Acervo",
      "summary": "WebSocket do estado do original. Gêmea HTTP: GET /preparo.",
      "desc": "Use wss no mesmo domínio e Origin exato. O canal só envia o mesmo JSON do GET; não recebe comandos. Uma consulta por documento atende todas as abas: a cada 5 segundos durante o download e a cada minuto na fila. Tetos por processo: 32 documentos, 128 conexões e quatro por rede. Duração máxima de 15 minutos. Fecha ao terminar ou ficar sem conexões. Ao voltar à aba, consulte o GET e reconecte. Nenhum conteúdo ou token privado é enviado.",
      "params": {
        "id": {
          "desc": "ID positivo do documento retornado pela compra.",
          "exemplo": "4806436"
        }
      },
      "retorno": {
        "_texto": "WebSocket: mensagens JSON com o mesmo data do GET /preparo."
      },
      "erros": {
        "400": "ID ou query inválido.",
        "403": "Origin diferente do domínio do canal.",
        "404": "Documento não encontrado. O servidor recusa antes de abrir o canal.",
        "426": "Upgrade para WebSocket necessário.",
        "429": "Limite de conexões. Retry-After: 60.",
        "503": "Canal indisponível."
      },
      "exemplo": "WebSocket $ORIGIN/api/documento/4806436/preparo/canal; troque https por wss; Origin: $ORIGIN",
      "returns": "WebSocket: mensagens JSON com o mesmo data do GET /preparo.",
      "url": "https://editalmd.com/api/documento/:id/preparo/canal",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/documento/:id",
      "auth": "none",
      "grupo": "Acervo",
      "summary": "Título, tipo, páginas e compra vinculada ao documento. Consulta pública, sem iniciar extração.",
      "params": {
        "id": {
          "desc": "Identificador do documento.",
          "exemplo": "93998"
        }
      },
      "retorno": {
        "documento": {
          "tipo": "object",
          "desc": "id, titulo, tipo, paginas (null quando desconhecidas), tem_texto, tem_binario, disponivel e gratuito. Não inclui texto, arquivos ou caminhos internos."
        },
        "compra_id": {
          "tipo": "int",
          "nulo": true,
          "desc": "Compra vinculada. Consulte /api/compra/:id para listar seus documentos com títulos, tipos e páginas (até 50 por ficha)."
        }
      },
      "erros": {
        "400": "ID inválido.",
        "404": "Documento não encontrado.",
        "502": "Origem indisponível."
      },
      "exemplo": "curl -s $ORIGIN/api/documento/93998",
      "returns": "{ documento, compra_id }",
      "url": "https://editalmd.com/api/documento/:id",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/documento/:id/markdown",
      "auth": "acesso",
      "params": {
        "id": {
          "desc": "Identificador do documento, vindo da ficha da compra.",
          "exemplo": "123"
        }
      },
      "summary": "Markdown com procedência e hash, com acesso comprado ou premium patrocinado. Exemplos gratuitos.",
      "grupo": "Acervo",
      "retorno": {
        "_texto": "`text/markdown`. Headers: `x-editalmd-regime`, `x-editalmd-sha256`. Leitura não gera recibo ou cobrança."
      },
      "erros": {
        "202": "Texto em preparação no acervo (`extracao_em_andamento`): `retry_after_s` no corpo e `Retry-After` no header. Repita após esse prazo. A preparação ainda não é uma entrega concluída.",
        "402": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; os exemplos são gratuitos.",
        "404": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente.",
        "409": "Texto indisponível ou geração necessária. Use geracao_url para consultar páginas e total e autorizar o pagamento.",
        "502": "Origem indisponível; nenhuma cobrança na leitura."
      },
      "exemplo": "curl -s $ORIGIN/api/documento/123/markdown",
      "headers": {
        "X-Agent-Pass": {
          "tipo": "string",
          "desc": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
        },
        "X-Editalmd-Avaliacao": {
          "tipo": "string",
          "desc": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
        },
        "X-Editalmd-Acesso": {
          "tipo": "string",
          "desc": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
        }
      },
      "returns": "`text/markdown`. Headers: `x-editalmd-regime`, `x-editalmd-sha256`. Leitura não gera recibo ou cobrança.",
      "url": "https://editalmd.com/api/documento/:id/markdown",
      "auth_detail": "Sessão da conta com aquisição vinculada, X-Editalmd-Acesso de compra anônima, ou X-Editalmd-Avaliacao junto de X-Agent-Pass para o documento patrocinado. Depois do vínculo da compra, exige conta. Os exemplos são livres."
    },
    {
      "method": "POST",
      "path": "/api/documento/:id/habilitacao",
      "auth": "acesso",
      "params": {
        "id": {
          "desc": "Identificador do documento, vindo da ficha da compra.",
          "exemplo": "123"
        }
      },
      "summary": "Lista de habilitação com trechos literais. Exige acesso ao documento comprado; sem cobrança adicional nesta fase.",
      "grupo": "Acervo",
      "desc": "Condições, exceções e evidências por página da análise disponível. A consulta não inicia outra análise. Prazos, propostas e demais obrigações estão no dossie; esta lista cobre habilitação e atestados exigidos, sem afirmar o que a empresa possui.",
      "retorno": "Habilitacao",
      "erros": {
        "402": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; os exemplos são gratuitos.",
        "404": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente.",
        "409": "Dossiê ainda em preparação. Nenhuma nova análise é iniciada por esta consulta.",
        "502": "Dossiê inválido ou resposta incompleta da origem.",
        "503": "Dossiê temporariamente indisponível."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/documento/123/habilitacao",
      "headers": {
        "X-Agent-Pass": {
          "tipo": "string",
          "desc": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
        },
        "X-Editalmd-Avaliacao": {
          "tipo": "string",
          "desc": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
        },
        "X-Editalmd-Acesso": {
          "tipo": "string",
          "desc": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
        }
      },
      "returns": "{ documento_id, compra_id, sha256_texto, dossie_versao, modelo, cache, recibo, recibo_url, aviso, habilitacao{juridica,fiscal_social_trabalhista,economico_financeira,tecnica,exclusivo_me_epp,impugnacao_texto,proposta_texto,total,descartados} }",
      "url": "https://editalmd.com/api/documento/:id/habilitacao",
      "auth_detail": "Sessão da conta com aquisição vinculada, X-Editalmd-Acesso de compra anônima, ou X-Editalmd-Avaliacao junto de X-Agent-Pass para o documento patrocinado. Depois do vínculo da compra, exige conta. Os exemplos são livres."
    },
    {
      "method": "POST",
      "path": "/api/dono",
      "auth": "none",
      "summary": "Cria o convidado (token edm_…) que abre alertas e vigias, e o segredo que assina os webhooks. Sem cadastro.",
      "grupo": "Acompanhar",
      "desc": "O token é emitido e assinado pela biblioteca de conta, com teto por rede e por hora, para a franquia grátis não virar infinita. Ele é mostrado uma única vez e não tem recuperação — entre na conta e traga as listas para ela (`POST /api/auth/claim`, que a página da conta faz sozinha ao entrar) para não depender dele. O `webhook_segredo` pode ser relido em `GET /api/dono`. Todo POST do webhook leva `webhook-id`, `webhook-timestamp` (segundos Unix) e `webhook-signature: v1,<base64>`: HMAC-SHA256 de `id.timestamp.corpo` com a chave do seu `whsec_…` (o base64 depois do prefixo). É o padrão Standard Webhooks — qualquer biblioteca dele confere; rejeite timestamp fora de 5 minutos. Depois de `POST /api/dono/segredo`, o anterior ainda assina por 24 h (duas partes `v1,` no cabeçalho).",
      "retorno": "Dono",
      "erros": {
        "429": "A rede passou do teto de convidados da hora.",
        "503": "Conta ou banco indisponível."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/dono",
      "returns": "{ token, aviso, webhook_segredo, webhook_assinatura, franquia }",
      "url": "https://editalmd.com/api/dono",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/dono",
      "auth": "owner",
      "summary": "O estado do dono: conta ou convidado, e-mail dos avisos, franquia e o segredo que assina os webhooks.",
      "grupo": "Acompanhar",
      "desc": "Todo POST do webhook leva `webhook-id`, `webhook-timestamp` (segundos Unix) e `webhook-signature: v1,<base64>`: HMAC-SHA256 de `id.timestamp.corpo` com a chave do seu `whsec_…` (o base64 depois do prefixo). É o padrão Standard Webhooks — qualquer biblioteca dele confere; rejeite timestamp fora de 5 minutos. Depois de `POST /api/dono/segredo`, o anterior ainda assina por 24 h (duas partes `v1,` no cabeçalho).",
      "retorno": {
        "tipo": {
          "tipo": "string",
          "desc": "`conta` (sessão) ou `convidado` (token edm_…)."
        },
        "email_alertas": {
          "tipo": "string",
          "desc": "E-mail verificado da conta, mascarado, para onde vão os avisos do canal e-mail; nulo no convidado.",
          "nulo": true
        },
        "webhook_segredo": {
          "tipo": "string",
          "desc": "`whsec_…` — a chave que assina cada POST de webhook."
        },
        "assinatura": {
          "tipo": "string",
          "desc": "Como conferir a assinatura, em uma linha."
        },
        "franquia": {
          "tipo": "object",
          "desc": "`alertas_gratis` e `vigias_gratis` incluídos."
        }
      },
      "erros": {
        "401": "Sem token de convidado nem sessão da conta, token desconhecido, credencial da carteira recusada (`invalid_wallet_token`), ou `session_ended` (cookie de sessão vencida: entre de novo).",
        "403": "`invalid_origin` / `invalid_csrf`: escrita com o cookie da conta fora da mesma origem ou sem X-CSRF-Token.",
        "503": "`conta_indisponivel`: conta fora do ar agora; nada muda."
      },
      "exemplo": "curl -s $ORIGIN/api/dono -H \"Authorization: Bearer $EDM\"",
      "returns": "{ tipo, email_alertas, webhook_segredo, assinatura, franquia }",
      "url": "https://editalmd.com/api/dono",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "POST",
      "path": "/api/dono/segredo",
      "auth": "owner",
      "summary": "Rotaciona o segredo do webhook. O anterior ainda assina por 24 h, para trocar sem janela de falha.",
      "grupo": "Acompanhar",
      "desc": "Durante as 24 h o cabeçalho `webhook-signature` traz duas partes `v1,…`: uma com o novo, outra com o anterior. Basta o receptor aceitar qualquer uma que bata.",
      "retorno": {
        "webhook_segredo": {
          "tipo": "string",
          "desc": "O novo `whsec_…`."
        },
        "anterior_valido_ate": {
          "tipo": "string",
          "desc": "Até quando o segredo anterior ainda assina (ISO 8601)."
        }
      },
      "erros": {
        "401": "Sem token de convidado nem sessão da conta, token desconhecido, credencial da carteira recusada (`invalid_wallet_token`), ou `session_ended` (cookie de sessão vencida: entre de novo).",
        "403": "`invalid_origin` / `invalid_csrf`: escrita com o cookie da conta fora da mesma origem ou sem X-CSRF-Token.",
        "503": "`conta_indisponivel`: conta fora do ar agora; nada muda."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/dono/segredo -H \"Authorization: Bearer $EDM\"",
      "returns": "{ webhook_segredo, anterior_valido_ate }",
      "url": "https://editalmd.com/api/dono/segredo",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "GET",
      "path": "/api/documento/:id/geracao",
      "auth": "none",
      "grupo": "Acervo",
      "summary": "Estado, cotação e direito de acesso; consulta gratuita, sem iniciar processamento.",
      "headers": {
        "X-Agent-Pass": {
          "tipo": "string",
          "desc": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
        },
        "X-Editalmd-Avaliacao": {
          "tipo": "string",
          "desc": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
        },
        "X-Editalmd-Acesso": {
          "tipo": "string",
          "desc": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
        }
      },
      "params": {
        "id": {
          "desc": "ID positivo do documento retornado pela compra.",
          "exemplo": "2110000"
        }
      },
      "retorno": {
        "documento_id": {
          "tipo": "int",
          "desc": "Documento solicitado."
        },
        "status": {
          "tipo": "string",
          "desc": "`pronto` quando a leitura pode ser aberta.",
          "opcional": true
        },
        "error": {
          "tipo": "string",
          "desc": "`geracao_necessaria`, `extracao_em_andamento`, `geracao_falhou` ou causa da indisponibilidade.",
          "opcional": true
        },
        "retry_after_s": {
          "tipo": "int",
          "desc": "Intervalo mínimo até o próximo GET de acompanhamento.",
          "opcional": true
        },
        "processing": {
          "tipo": "object",
          "desc": "Progresso real: `progress.stage` (preparing, reading, verifying, packaging), `pages_total`, `pages_processed`, `pages_completed`, `pass`; `updated_at` e `elapsed_ms`.",
          "opcional": true
        },
        "markdown_url": {
          "tipo": "string",
          "desc": "GET do Markdown, com o acesso comprado."
        },
        "geracao_url": {
          "tipo": "string",
          "desc": "GET para estado/cotação; POST para comprar acesso individual."
        },
        "acesso_comprado": {
          "tipo": "boolean",
          "desc": "Esta credencial pode ler o documento, independentemente do estado global do texto."
        },
        "acesso": {
          "tipo": "object",
          "opcional": true,
          "desc": "Após pagamento confirmado fora da sessão da conta: codigo privado e header X-Editalmd-Acesso. Guarde para reabrir ou para vincular a uma conta (POST /vincular). Não publique, não abre outro documento."
        },
        "preco_pagina_usd": {
          "tipo": "string",
          "desc": "US$ 0,02 por página no site e API (x402 ou crédito)."
        },
        "cotacao": {
          "tipo": "object",
          "desc": "Páginas confirmadas no documento: paginas, source_sha256, preco_pagina_usd e preco_total_usd, e os mesmos em reais no câmbio fixo do Pix da casa (preco_pagina_brl, preco_total_brl), com o menor pacote de crédito em reais (pacote_minimo_brl) e quantos documentos como este ele rende (documentos_no_pacote). Nulo quando não é possível cotar. A compra confere só paginas, source_sha256 e preco_total_usd.",
          "nulo": true
        },
        "pagamento": {
          "tipo": "object",
          "desc": "Quando cobrado: `recibo` da porta x402/crédito e `preco_usd`. Conserve mesmo se a origem falhar.",
          "opcional": true
        }
      },
      "erros": {
        "202": "Processamento em curso; acompanhe por GET, respeitando Retry-After. Nunca repita POST para fazer polling.",
        "404": "Documento inexistente.",
        "409": "Geração necessária, falha anterior ou binário indisponível; consulte `error`.",
        "502": "Origem indisponível; repita o GET depois do Retry-After e não repita pagamento sem conferir o estado e o recibo."
      },
      "exemplo": "curl -s $ORIGIN/api/documento/1993401/geracao",
      "returns": "{ documento_id, status?, error?, retry_after_s?, processing?, markdown_url, geracao_url, acesso_comprado, acesso?, preco_pagina_usd, cotacao, pagamento? }",
      "url": "https://editalmd.com/api/documento/:id/geracao",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/documento/:id/geracao",
      "auth": "none",
      "grupo": "Acervo",
      "summary": "Compra acesso individual ao documento por US$ 0,02/página, via x402/crédito.",
      "desc": "Cada comprador paga, inclusive pronto. Consulte GET ou 402, confira páginas/hash/total e envie cotacao. Sessão da conta (cookie + CSRF do navegador) grava a compra no direito global da conta antes da entrega, sem código avulso; com o convidado edm_… (Bearer), o direito é dele e o código sai junto; agente usa X-Credito. Sem conta, conserve acesso.codigo para reabrir ou vincular depois. Após vínculo somente a conta abre. Texto pronto reutiliza OCR; geração necessária incluída. Cotação desconhecida/alterada não cobra. 152 páginas = US$ 3,04. Corpo até 4096 bytes. Após 202 acompanhe por GET. Pagou e a gravação do direito falhou: 502 `pago_nao_registrado` com o `recibo` — guarde-o, o suporte entrega ou estorna.",
      "params": {
        "id": {
          "desc": "ID positivo do documento retornado pela compra.",
          "exemplo": "2110000"
        }
      },
      "retorno": {
        "documento_id": {
          "tipo": "int",
          "desc": "Documento solicitado."
        },
        "status": {
          "tipo": "string",
          "desc": "`pronto` quando a leitura pode ser aberta.",
          "opcional": true
        },
        "error": {
          "tipo": "string",
          "desc": "`geracao_necessaria`, `extracao_em_andamento`, `geracao_falhou` ou causa da indisponibilidade.",
          "opcional": true
        },
        "retry_after_s": {
          "tipo": "int",
          "desc": "Intervalo mínimo até o próximo GET de acompanhamento.",
          "opcional": true
        },
        "processing": {
          "tipo": "object",
          "desc": "Progresso real: `progress.stage` (preparing, reading, verifying, packaging), `pages_total`, `pages_processed`, `pages_completed`, `pass`; `updated_at` e `elapsed_ms`.",
          "opcional": true
        },
        "markdown_url": {
          "tipo": "string",
          "desc": "GET do Markdown, com o acesso comprado."
        },
        "geracao_url": {
          "tipo": "string",
          "desc": "GET para estado/cotação; POST para comprar acesso individual."
        },
        "acesso_comprado": {
          "tipo": "boolean",
          "desc": "Esta credencial pode ler o documento, independentemente do estado global do texto."
        },
        "acesso": {
          "tipo": "object",
          "opcional": true,
          "desc": "Após pagamento confirmado fora da sessão da conta: codigo privado e header X-Editalmd-Acesso. Guarde para reabrir ou para vincular a uma conta (POST /vincular). Não publique, não abre outro documento."
        },
        "preco_pagina_usd": {
          "tipo": "string",
          "desc": "US$ 0,02 por página no site e API (x402 ou crédito)."
        },
        "cotacao": {
          "tipo": "object",
          "desc": "Páginas confirmadas no documento: paginas, source_sha256, preco_pagina_usd e preco_total_usd, e os mesmos em reais no câmbio fixo do Pix da casa (preco_pagina_brl, preco_total_brl), com o menor pacote de crédito em reais (pacote_minimo_brl) e quantos documentos como este ele rende (documentos_no_pacote). Nulo quando não é possível cotar. A compra confere só paginas, source_sha256 e preco_total_usd.",
          "nulo": true
        },
        "pagamento": {
          "tipo": "object",
          "desc": "Quando cobrado: `recibo` da porta x402/crédito e `preco_usd`. Conserve mesmo se a origem falhar.",
          "opcional": true
        }
      },
      "corpo": {
        "cotacao": {
          "tipo": "object",
          "desc": "Objeto recebido no GET/402: paginas, source_sha256 e preco_total_usd devem coincidir com a cotação atual. Obrigatório ao enviar autorização de pagamento."
        }
      },
      "headers": {
        "X-Agent-Pass": {
          "tipo": "string",
          "desc": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
        },
        "X-Editalmd-Avaliacao": {
          "tipo": "string",
          "desc": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
        },
        "X-Editalmd-Acesso": {
          "tipo": "string",
          "desc": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
        },
        "X-PAYMENT": {
          "tipo": "string",
          "desc": "Autorização x402 do desafio 402."
        },
        "X-Credito": {
          "tipo": "string",
          "desc": "Token cred_… para descontar do saldo, como alternativa ao x402."
        },
        "Authorization": {
          "tipo": "string",
          "desc": "Bearer cred_… é alternativa ao X-Credito. A conta viaja em cookie, nunca em bearer."
        },
        "Idempotency-Key": {
          "tipo": "string",
          "desc": "Chave de tentativa, até 80 caracteres; preserve em retries de crédito do mesmo documento."
        }
      },
      "erros": {
        "202": "Processamento em curso; acompanhe por GET, respeitando Retry-After. Nunca repita POST para fazer polling.",
        "400": "Corpo malformado ou campos desconhecidos.",
        "401": "Crédito inválido, ou `session_ended` (cookie de sessão vencida: entre de novo); nada cobrado.",
        "402": "Pagamento necessário ou recusado; anuncia x402, crédito e cotação.",
        "403": "`invalid_origin` / `invalid_csrf`: compra com o cookie da conta exige a mesma origem e X-CSRF-Token; nada cobrado.",
        "404": "Documento inexistente.",
        "409": "Cotação alterada/ausente, páginas desconhecidas ou geração indisponível; nada cobrado antes da autorização.",
        "413": "Corpo excedeu 4096 bytes.",
        "502": "Origem indisponível; não repita pagamento sem conferir o estado e o recibo. `pago_nao_registrado`: pagou e a gravação do direito falhou — guarde o `recibo`.",
        "503": "Pagamento sem configuração, `conta_indisponivel` ou `acesso_exige_pagamento` (documento nunca sai de graça); nada cobrado."
      },
      "exemplo": "curl -s -X POST $ORIGIN/api/documento/1993401/geracao -H \"Content-Type: application/json\" -d '{}'",
      "returns": "{ documento_id, status?, error?, retry_after_s?, processing?, markdown_url, geracao_url, acesso_comprado, acesso?, preco_pagina_usd, cotacao, pagamento? }",
      "url": "https://editalmd.com/api/documento/:id/geracao",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/exemplos",
      "auth": "none",
      "grupo": "Acervo",
      "summary": "Galeria de documentos reais já processados: leitura, original, Markdown e ZIP gratuitos.",
      "retorno": {
        "_texto": "HTML com exemplos prontos. Abrir ou baixar não gera processamento nem cobrança."
      },
      "exemplo": "curl -fsS $ORIGIN/exemplos",
      "returns": "HTML com exemplos prontos. Abrir ou baixar não gera processamento nem cobrança.",
      "url": "https://editalmd.com/exemplos",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/entregas",
      "auth": "none",
      "grupo": "Acervo",
      "summary": "Exemplos do que se recebe, marcados como exemplo: o relatório completo do preço que ganha, a pesquisa de preços, a análise assistida e o edital organizado, com dados reais.",
      "retorno": {
        "_texto": "HTML com uma seção por entrega (a âncora que o \"Ver exemplo\" da ficha abre)."
      },
      "exemplo": "curl -fsS $ORIGIN/entregas",
      "returns": "HTML com uma seção por entrega (a âncora que o \"Ver exemplo\" da ficha abre).",
      "url": "https://editalmd.com/entregas",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/exemplos",
      "auth": "none",
      "grupo": "Acervo",
      "summary": "Exemplos prontos, com procedência, páginas, imagens, SHA-256 e links de leitura e download.",
      "retorno": {
        "exemplos": {
          "tipo": "object[]",
          "desc": "documento_id, compra_id, titulo, local, descricao, paginas, imagens, sha256, gratuito=true, leitura_url, markdown_url, manifesto_url, original_url, arquivos_url e pacote_url."
        }
      },
      "exemplo": "curl -fsS $ORIGIN/api/exemplos",
      "returns": "{ exemplos }",
      "url": "https://editalmd.com/api/exemplos",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/documento/:id/cobranca",
      "auth": "cobranca",
      "grupo": "Acervo",
      "summary": "Reserva endereço/QR exclusivo para comprar seu acesso com USDC na Base.",
      "desc": "Consulte GET /geracao e envie cotacao. Cada comprador paga, inclusive pronto. O serviço confirma USDC no bloco safe da Base; safe aguarda inclusão na L1, sem finalidade absoluta. Envie em até 30 min; observação por 24 h. Pagamento tardio, rede/moeda errada ou extração falha exige atendimento. Carteira/corretora pode cobrar taxa. Mesma X-Cobranca conserva cobrança/endereço. GET pago devolve acesso.codigo e cookie; para guardar na conta, POST /api/documento/:id/vincular com esse código (o site faz isso sozinho para quem está conectado). O pagamento simulado do ambiente de desenvolvimento não vale para depósito.",
      "params": {
        "id": {
          "desc": "ID positivo do documento.",
          "exemplo": "2110000"
        }
      },
      "headers": {
        "X-Cobranca": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "32 bytes aleatórios em 64 caracteres hex minúsculos. Gere e guarde antes do POST; reutilize no GET e em retries. Segredo de acesso à sua cobrança."
        }
      },
      "retorno": {
        "acesso": {
          "tipo": "object",
          "opcional": true,
          "desc": "Após pagamento confirmado fora da sessão da conta: codigo privado e header X-Editalmd-Acesso. Guarde para reabrir ou para vincular a uma conta (POST /vincular). Não publique, não abre outro documento."
        },
        "id": {
          "tipo": "string",
          "desc": "Identificador da cobrança, para atendimento."
        },
        "documento_id": {
          "tipo": "int",
          "desc": "Documento cotado."
        },
        "rede": {
          "tipo": "string",
          "desc": "base; base-sepolia só no ambiente de desenvolvimento."
        },
        "chain_id": {
          "tipo": "int",
          "desc": "8453 em produção, 84532 no teste."
        },
        "moeda": {
          "tipo": "string",
          "desc": "USDC."
        },
        "contrato": {
          "tipo": "string",
          "desc": "Contrato USDC aceito nesta rede."
        },
        "endereco": {
          "tipo": "string",
          "desc": "Endereço exclusivo desta cobrança. Nunca reutilize para outra."
        },
        "paginas": {
          "tipo": "int",
          "desc": "Páginas físicas confirmadas no documento."
        },
        "preco_total_usd": {
          "tipo": "string",
          "desc": "Páginas × US$ 0,02; valor em USDC equivalente."
        },
        "recebido_usdc": {
          "tipo": "string",
          "desc": "Soma de transferências confirmadas, seis casas decimais."
        },
        "restante_usdc": {
          "tipo": "string",
          "desc": "Valor que falta; taxas da carteira/corretora não entram."
        },
        "status": {
          "tipo": "string",
          "desc": "aguardando, expirada, pago, solicitada, gerando, pronto ou revisao."
        },
        "expira_em": {
          "tipo": "string",
          "desc": "ISO UTC: envie em até 30 minutos."
        },
        "verificada_em": {
          "tipo": "string",
          "nulo": true,
          "desc": "Última observação da rede pelo servidor."
        },
        "detalhe": {
          "tipo": "string",
          "nulo": true,
          "desc": "Orientação quando precisar de atendimento."
        },
        "retry_after_s": {
          "tipo": "int",
          "desc": "30 segundos entre consultas."
        },
        "pagamento_uri": {
          "tipo": "string",
          "nulo": true,
          "desc": "URI EIP-681 para carteira/QR, com rede, contrato, destinatário e valor restante. Ausente após vencer ou pagar."
        },
        "transacoes": {
          "tipo": "object[]",
          "desc": "hash, valor_usdc e url do explorador para cada transferência."
        }
      },
      "erros": {
        "400": "Documento/corpo inválido ou cotação ausente.",
        "401": "X-Cobranca inválido.",
        "404": "Cobrança inexistente para este documento e token.",
        "409": "Cotação alterada, páginas desconhecidas ou teto de cobranças atingido; não envie dinheiro.",
        "413": "Corpo maior que 4096 bytes.",
        "502": "Origem indisponível.",
        "503": "Checkout por depósito indisponível."
      },
      "corpo": {
        "cotacao": {
          "tipo": "object",
          "obrigatorio": true,
          "desc": "Cotação recebida no GET /geracao: paginas, source_sha256 e preco_total_usd."
        }
      },
      "exemplo": "curl -s -X POST $ORIGIN/api/documento/1993401/cobranca -H 'X-Cobranca: SEU_TOKEN_64_HEX' -H 'Content-Type: application/json' --data @cotacao.json",
      "returns": "{ acesso?, id, documento_id, rede, chain_id, moeda, contrato, endereco, paginas, preco_total_usd, recebido_usdc, restante_usdc, status, expira_em, verificada_em, detalhe, retry_after_s, pagamento_uri, transacoes }",
      "url": "https://editalmd.com/api/documento/:id/cobranca",
      "auth_detail": "X-Cobranca: token de 64 hex minúsculos escolhido aleatoriamente pelo cliente; conserve para consultar e retomar sua cobrança."
    },
    {
      "method": "GET",
      "path": "/api/documento/:id/cobranca",
      "auth": "cobranca",
      "grupo": "Acervo",
      "summary": "Consulta endereço, confirmação, recibo e liberação da sua cobrança gratuitamente.",
      "desc": "Reutilize X-Cobranca e respeite Retry-After. Consulta não escreve nem faz RPC blockchain. Quando gerando, use GET /geracao para fases/páginas; pronto libera os links de leitura. Em revisao, conserve ID e transações para atendimento, sem pagar novamente.",
      "params": {
        "id": {
          "desc": "ID positivo do documento.",
          "exemplo": "2110000"
        }
      },
      "headers": {
        "X-Cobranca": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "32 bytes aleatórios em 64 caracteres hex minúsculos. Gere e guarde antes do POST; reutilize no GET e em retries. Segredo de acesso à sua cobrança."
        }
      },
      "retorno": {
        "acesso": {
          "tipo": "object",
          "opcional": true,
          "desc": "Após pagamento confirmado fora da sessão da conta: codigo privado e header X-Editalmd-Acesso. Guarde para reabrir ou para vincular a uma conta (POST /vincular). Não publique, não abre outro documento."
        },
        "id": {
          "tipo": "string",
          "desc": "Identificador da cobrança, para atendimento."
        },
        "documento_id": {
          "tipo": "int",
          "desc": "Documento cotado."
        },
        "rede": {
          "tipo": "string",
          "desc": "base; base-sepolia só no ambiente de desenvolvimento."
        },
        "chain_id": {
          "tipo": "int",
          "desc": "8453 em produção, 84532 no teste."
        },
        "moeda": {
          "tipo": "string",
          "desc": "USDC."
        },
        "contrato": {
          "tipo": "string",
          "desc": "Contrato USDC aceito nesta rede."
        },
        "endereco": {
          "tipo": "string",
          "desc": "Endereço exclusivo desta cobrança. Nunca reutilize para outra."
        },
        "paginas": {
          "tipo": "int",
          "desc": "Páginas físicas confirmadas no documento."
        },
        "preco_total_usd": {
          "tipo": "string",
          "desc": "Páginas × US$ 0,02; valor em USDC equivalente."
        },
        "recebido_usdc": {
          "tipo": "string",
          "desc": "Soma de transferências confirmadas, seis casas decimais."
        },
        "restante_usdc": {
          "tipo": "string",
          "desc": "Valor que falta; taxas da carteira/corretora não entram."
        },
        "status": {
          "tipo": "string",
          "desc": "aguardando, expirada, pago, solicitada, gerando, pronto ou revisao."
        },
        "expira_em": {
          "tipo": "string",
          "desc": "ISO UTC: envie em até 30 minutos."
        },
        "verificada_em": {
          "tipo": "string",
          "nulo": true,
          "desc": "Última observação da rede pelo servidor."
        },
        "detalhe": {
          "tipo": "string",
          "nulo": true,
          "desc": "Orientação quando precisar de atendimento."
        },
        "retry_after_s": {
          "tipo": "int",
          "desc": "30 segundos entre consultas."
        },
        "pagamento_uri": {
          "tipo": "string",
          "nulo": true,
          "desc": "URI EIP-681 para carteira/QR, com rede, contrato, destinatário e valor restante. Ausente após vencer ou pagar."
        },
        "transacoes": {
          "tipo": "object[]",
          "desc": "hash, valor_usdc e url do explorador para cada transferência."
        }
      },
      "erros": {
        "400": "Documento/corpo inválido ou cotação ausente.",
        "401": "X-Cobranca inválido.",
        "404": "Cobrança inexistente para este documento e token.",
        "409": "Cotação alterada, páginas desconhecidas ou teto de cobranças atingido; não envie dinheiro.",
        "413": "Corpo maior que 4096 bytes.",
        "502": "Origem indisponível.",
        "503": "Checkout por depósito indisponível."
      },
      "exemplo": "curl -s $ORIGIN/api/documento/1993401/cobranca -H 'X-Cobranca: SEU_TOKEN_64_HEX'",
      "returns": "{ acesso?, id, documento_id, rede, chain_id, moeda, contrato, endereco, paginas, preco_total_usd, recebido_usdc, restante_usdc, status, expira_em, verificada_em, detalhe, retry_after_s, pagamento_uri, transacoes }",
      "url": "https://editalmd.com/api/documento/:id/cobranca",
      "auth_detail": "X-Cobranca: token de 64 hex minúsculos escolhido aleatoriamente pelo cliente; conserve para consultar e retomar sua cobrança."
    },
    {
      "method": "POST",
      "path": "/api/cobranca/:id/registrar",
      "auth": "origem",
      "grupo": "Operação",
      "summary": "Operação interna para registrar transferência confirmada no razão financeiro.",
      "desc": "Uso exclusivo da origem autenticada. A prova é verificada pelo serviço, nunca aceita do corpo. Repetição registra cada evento uma única vez.",
      "params": {
        "id": {
          "desc": "UUID da cobrança.",
          "exemplo": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
        }
      },
      "headers": {
        "X-Editalmd-Secret": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Segredo compartilhado da origem; somente operador."
        }
      },
      "retorno": {
        "registrado": {
          "tipo": "boolean",
          "desc": "Todos os eventos registrados ou já existentes."
        }
      },
      "erros": {
        "401": "Sem autoridade da origem.",
        "404": "Cobrança inexistente na origem.",
        "409": "Pagamento não confirmado.",
        "503": "Registro indisponível; tente novamente conforme a orientação do serviço."
      },
      "exemplo": "curl -s -X POST $ORIGIN/api/cobranca/UUID/registrar -H 'X-Editalmd-Secret: SEGREDO_DA_ORIGEM'",
      "returns": "{ registrado }",
      "url": "https://editalmd.com/api/cobranca/:id/registrar",
      "auth_detail": "X-Editalmd-Secret: credencial privada de integração interna. Não é uma porta para clientes ou agentes públicos."
    },
    {
      "method": "GET",
      "path": "/api/documento/:id/dossie",
      "auth": "acesso",
      "grupo": "Acervo",
      "params": {
        "id": {
          "desc": "Identificador do documento na ficha da compra.",
          "exemplo": "9558909"
        }
      },
      "summary": "Dados estruturados: exigências, itens, atestados, prazos, condições e evidências por página.",
      "desc": "Dossiê incluído no acesso documental, sem nova análise ao consultar. Dados parciais informam cobertura; exportação exige versão concluída.",
      "query": {
        "v": {
          "tipo": "string",
          "desc": "SHA-256 do texto exibido; recusa versão diferente."
        },
        "after": {
          "tipo": "integer",
          "desc": "Cursor next anterior, padrão 0."
        },
        "limit": {
          "tipo": "integer",
          "desc": "1 a 30 registros, padrão 30."
        },
        "kind": {
          "tipo": "string",
          "desc": "identity, item, requirement, attestation, deadline ou obligation."
        },
        "format": {
          "tipo": "string",
          "desc": "page (padrão) ou json para download completo sem filtro/paginação."
        }
      },
      "retorno": {
        "_texto": "Página: data.version, data.complete, data.facts e data.next. Fatos conservam details tipados, applicability, exceptions, evidence (page/start/end/quote) e references. Duração exige quantidade e unidade associadas na evidência; duration_verification identifica correção ou revisão necessária, sem alterar a fonte. format=json: schema licitech-document-dossier-v1, version e facts completos, até 16 MiB."
      },
      "erros": {
        "400": "Consulta inválida.",
        "402": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; os exemplos são gratuitos.",
        "404": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente.",
        "409": "Versão mudou ou exportação ainda em preparo.",
        "502": "Origem indisponível."
      },
      "exemplo": "curl -fsS \"$ORIGIN/api/documento/1993401/dossie?kind=deadline&limit=20\"",
      "headers": {
        "X-Agent-Pass": {
          "tipo": "string",
          "desc": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
        },
        "X-Editalmd-Avaliacao": {
          "tipo": "string",
          "desc": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
        },
        "X-Editalmd-Acesso": {
          "tipo": "string",
          "desc": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
        }
      },
      "agent_value": {
        "principal": true,
        "idioma": "pt",
        "en": {
          "when": "What does this tender require, and on which page?",
          "result": "Structured requirements, items, deadlines, conditions and exceptions with page evidence, version and coverage.",
          "replaces": "We convert the document and link extracted requirements to page evidence. Start from the prepared dossier instead of rebuilding that extraction.",
          "free": "Find the tender with free search. Inspect /api/exemplos or the evaluation at /avaliacao.md before buying processed access.",
          "paid": "The prepared dossier is included in the document's paid access. Check the file's readiness and compare its quote with current plan allowances.",
          "limits": "Inspect complete, coverage and issues. An unfinished dossier is not evidence that a requirement is absent. Check the original and source dates before a bid decision.",
          "alternative": "You only need metadata or the original PDF, or the prepared evidence does not cover the document you need.",
          "start": {
            "href": "/",
            "label": "Find a tender"
          }
        },
        "pt": {
          "when": "O que este edital exige e em qual página?",
          "result": "Exigências, itens, prazos, condições e exceções estruturados, com evidência por página, versão e cobertura.",
          "replaces": "Convertemos o documento e ligamos as exigências às páginas de origem. Use o dossiê preparado sem refazer essa extração.",
          "free": "Encontre o edital na busca gratuita. Confira /api/exemplos ou a avaliação em /avaliacao.md antes de comprar o acesso processado.",
          "paid": "O dossiê preparado integra o acesso pago ao documento. Confira o preparo do arquivo e compare a cotação com a franquia dos planos vigentes.",
          "limits": "Confira complete, cobertura e problemas. Dossiê inacabado não prova ausência de exigência. Confira o original e as datas antes de decidir uma proposta.",
          "alternative": "Você precisa só dos metadados ou do PDF original, ou a evidência preparada não cobre o documento necessário.",
          "start": {
            "href": "/",
            "label": "Encontrar edital"
          }
        }
      },
      "returns": "Página: data.version, data.complete, data.facts e data.next. Fatos conservam details tipados, applicability, exceptions, evidence (page/start/end/quote) e references. Duração exige quantidade e unidade associadas na evidência; duration_verification identifica correção ou revisão necessária, sem alterar a fonte. format=json: schema licitech-document-dossier-v1, version e facts completos, até 16 MiB.",
      "url": "https://editalmd.com/api/documento/:id/dossie",
      "auth_detail": "Sessão da conta com aquisição vinculada, X-Editalmd-Acesso de compra anônima, ou X-Editalmd-Avaliacao junto de X-Agent-Pass para o documento patrocinado. Depois do vínculo da compra, exige conta. Os exemplos são livres."
    },
    {
      "method": "GET",
      "path": "/licitacoes/",
      "auth": "none",
      "grupo": "Acervo",
      "summary": "Navegação pública do acervo por modalidade, UF, data e município.",
      "retorno": {
        "_texto": "HTML com navegação do EditalMD. Cada recorte oferece links para JSON, Markdown e OKF dos metadados."
      },
      "exemplo": "curl -fsS $ORIGIN/licitacoes/",
      "returns": "HTML com navegação do EditalMD. Cada recorte oferece links para JSON, Markdown e OKF dos metadados.",
      "url": "https://editalmd.com/licitacoes/",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/licitacoes/compra/:id/",
      "auth": "none",
      "grupo": "Acervo",
      "params": {
        "id": {
          "desc": "Identificador da compra.",
          "exemplo": "1996190"
        }
      },
      "summary": "Ficha pública no aplicativo, com dados e filtros já renderizados no HTML.",
      "query": {
        "aba": {
          "tipo": "string",
          "desc": "licitacao (padrão), precos, requisitos, documentos ou fornece. Mantém a aba indicada ao abrir o aplicativo."
        },
        "financeiro_q": {
          "tipo": "string",
          "desc": "Termo preservado para a consulta de preços da compra."
        },
        "meses": {
          "tipo": "integer",
          "desc": "Período em meses usado pela consulta de preços."
        },
        "doc": {
          "tipo": "integer",
          "desc": "Documento a abrir."
        },
        "pagina": {
          "tipo": "integer",
          "desc": "Página inicial, a partir de 1."
        },
        "vista": {
          "tipo": "string",
          "desc": "leitura, markdown, dados, exigencias, original, arquivos ou procedencia."
        },
        "tipo": {
          "tipo": "string",
          "desc": "Subaba: dados usa identity, item ou deadline; exigencias usa requirement, attestation ou obligation."
        }
      },
      "retorno": {
        "_texto": "HTML público com o aplicativo na compra solicitada, sem dados privados da conta. A navegação preserva a URL, filtros e abas. Conta e recursos adicionais carregam após a abertura. Para dados estruturados, use /api/compra/:id e a família /api/documento/:id."
      },
      "erros": {
        "404": "Compra não encontrada."
      },
      "exemplo": "curl -fsS $ORIGIN/licitacoes/compra/1996190/",
      "returns": "HTML público com o aplicativo na compra solicitada, sem dados privados da conta. A navegação preserva a URL, filtros e abas. Conta e recursos adicionais carregam após a abertura. Para dados estruturados, use /api/compra/:id e a família /api/documento/:id.",
      "url": "https://editalmd.com/licitacoes/compra/:id/",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/documento/:id/original",
      "auth": "none",
      "grupo": "Acervo",
      "params": {
        "id": {
          "desc": "Identificador do documento na ficha da compra.",
          "exemplo": "9558909"
        }
      },
      "summary": "Abrir ou baixar gratuitamente o original preservado.",
      "desc": "Entrega o original público sem compra, conta ou nova extração. PDFs abrem no navegador; outros formatos são anexos. Conteúdo processado e análise continuam nas portas pagas.",
      "retorno": {
        "_texto": "Binário original (PDF, ZIP ou outro formato), até 96 MiB, com MIME e nome do arquivo."
      },
      "erros": {
        "404": "Original indisponível no acervo.",
        "502": "Origem indisponível."
      },
      "exemplo": "curl -fsS $ORIGIN/api/documento/9558909/original -o original",
      "returns": "Binário original (PDF, ZIP ou outro formato), até 96 MiB, com MIME e nome do arquivo.",
      "url": "https://editalmd.com/api/documento/:id/original",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/documento/:id/partes",
      "auth": "acesso",
      "grupo": "Acervo",
      "params": {
        "id": {
          "desc": "Identificador do documento na ficha da compra.",
          "exemplo": "9558909"
        }
      },
      "summary": "Arquivos internos disponíveis no documento comprado.",
      "retorno": {
        "data": {
          "tipo": "object",
          "desc": "document_id e parts (até 200): id, idx, label, content_type, size_bytes, page_count, page_offset e arquivo_url relativo a /api/documento/:id/partes/:partId/arquivo. Lista vazia indica documento sem peças."
        }
      },
      "erros": {
        "402": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; os exemplos são gratuitos.",
        "404": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente.",
        "409": "Arquivo ou índice ainda indisponível.",
        "422": "Pacote não pôde ser lido.",
        "502": "Origem indisponível.",
        "503": "Acervo ocupado; respeite Retry-After."
      },
      "exemplo": "curl -fsS $ORIGIN/api/documento/9558909/partes",
      "headers": {
        "X-Agent-Pass": {
          "tipo": "string",
          "desc": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
        },
        "X-Editalmd-Avaliacao": {
          "tipo": "string",
          "desc": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
        },
        "X-Editalmd-Acesso": {
          "tipo": "string",
          "desc": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
        }
      },
      "returns": "{ data }",
      "url": "https://editalmd.com/api/documento/:id/partes",
      "auth_detail": "Sessão da conta com aquisição vinculada, X-Editalmd-Acesso de compra anônima, ou X-Editalmd-Avaliacao junto de X-Agent-Pass para o documento patrocinado. Depois do vínculo da compra, exige conta. Os exemplos são livres."
    },
    {
      "method": "GET",
      "path": "/api/documento/:id/partes/:partId/arquivo",
      "auth": "acesso",
      "grupo": "Acervo",
      "params": {
        "id": {
          "desc": "Identificador do documento na ficha da compra.",
          "exemplo": "9558909"
        },
        "partId": {
          "desc": "id da peça retornado em partes.",
          "exemplo": "1"
        }
      },
      "summary": "Abrir ou baixar uma peça original com o acesso comprado ao documento.",
      "retorno": {
        "_texto": "Binário pronto, até 96 MiB. PDF pode ser exibido no navegador; outros formatos podem ser baixados."
      },
      "erros": {
        "402": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; os exemplos são gratuitos.",
        "404": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente.",
        "502": "Origem indisponível."
      },
      "exemplo": "curl -fsS $ORIGIN/api/documento/9558909/partes/1/arquivo -o arquivo.pdf",
      "headers": {
        "X-Agent-Pass": {
          "tipo": "string",
          "desc": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
        },
        "X-Editalmd-Avaliacao": {
          "tipo": "string",
          "desc": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
        },
        "X-Editalmd-Acesso": {
          "tipo": "string",
          "desc": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
        }
      },
      "returns": "Binário pronto, até 96 MiB. PDF pode ser exibido no navegador; outros formatos podem ser baixados.",
      "url": "https://editalmd.com/api/documento/:id/partes/:partId/arquivo",
      "auth_detail": "Sessão da conta com aquisição vinculada, X-Editalmd-Acesso de compra anônima, ou X-Editalmd-Avaliacao junto de X-Agent-Pass para o documento patrocinado. Depois do vínculo da compra, exige conta. Os exemplos são livres."
    },
    {
      "method": "GET",
      "path": "/api/documento/:id/leitura",
      "auth": "acesso",
      "grupo": "Acervo",
      "params": {
        "id": {
          "desc": "Identificador do documento na ficha da compra.",
          "exemplo": "9558909"
        }
      },
      "summary": "Manifesto do documento comprado: páginas físicas, imagens e hashes da extração atual.",
      "desc": "Somente recursos prontos. Não inicia OCR. `document_approved: false` identifica a extração automática e não impede sua leitura.",
      "retorno": {
        "data": {
          "tipo": "object",
          "desc": "schema licitech-document-package-v1; document_id, source_sha256, text_sha256, markdown_sha256, pages (number/start/end), images (sha256/filename/size_bytes/mime/width/height), occurrences (page/reference/start/end/sha256). Offsets UTF-16 de fonte.md."
        }
      },
      "erros": {
        "402": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; os exemplos são gratuitos.",
        "404": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente.",
        "409": "Versão do texto alterada; abra o manifesto atual.",
        "502": "Origem indisponível."
      },
      "exemplo": "curl -s $ORIGIN/api/documento/9558909/leitura",
      "headers": {
        "X-Agent-Pass": {
          "tipo": "string",
          "desc": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
        },
        "X-Editalmd-Avaliacao": {
          "tipo": "string",
          "desc": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
        },
        "X-Editalmd-Acesso": {
          "tipo": "string",
          "desc": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
        }
      },
      "returns": "{ data }",
      "url": "https://editalmd.com/api/documento/:id/leitura",
      "auth_detail": "Sessão da conta com aquisição vinculada, X-Editalmd-Acesso de compra anônima, ou X-Editalmd-Avaliacao junto de X-Agent-Pass para o documento patrocinado. Depois do vínculo da compra, exige conta. Os exemplos são livres."
    },
    {
      "method": "GET",
      "path": "/api/documento/:id/pacote",
      "auth": "acesso",
      "grupo": "Acervo",
      "params": {
        "id": {
          "desc": "Identificador do documento na ficha da compra.",
          "exemplo": "9558909"
        }
      },
      "summary": "Baixar ZIP com Markdown e imagens do documento comprado para leitura fora do site.",
      "query": {
        "v": {
          "tipo": "string",
          "desc": "text_sha256 do manifesto; fixa a versão exibida no leitor."
        }
      },
      "retorno": {
        "_texto": "`application/zip`, até 96 MiB: documento.md, pasta imagens, fonte.md literal, manifesto.json e LEIA-ME.txt. Mantenha a pasta imagens junto do Markdown."
      },
      "erros": {
        "400": "Versão inválida.",
        "402": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; os exemplos são gratuitos.",
        "404": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente.",
        "409": "Versão do texto alterada; abra o manifesto atual.",
        "502": "Origem indisponível."
      },
      "exemplo": "curl -fsS $ORIGIN/api/documento/9558909/pacote -o documento.zip",
      "headers": {
        "X-Agent-Pass": {
          "tipo": "string",
          "desc": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
        },
        "X-Editalmd-Avaliacao": {
          "tipo": "string",
          "desc": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
        },
        "X-Editalmd-Acesso": {
          "tipo": "string",
          "desc": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
        }
      },
      "returns": "`application/zip`, até 96 MiB: documento.md, pasta imagens, fonte.md literal, manifesto.json e LEIA-ME.txt. Mantenha a pasta imagens junto do Markdown.",
      "url": "https://editalmd.com/api/documento/:id/pacote",
      "auth_detail": "Sessão da conta com aquisição vinculada, X-Editalmd-Acesso de compra anônima, ou X-Editalmd-Avaliacao junto de X-Agent-Pass para o documento patrocinado. Depois do vínculo da compra, exige conta. Os exemplos são livres."
    },
    {
      "method": "GET",
      "path": "/api/documento/:id/imagens/:version/:imageSha",
      "auth": "acesso",
      "grupo": "Acervo",
      "params": {
        "id": {
          "desc": "Identificador do documento na ficha da compra.",
          "exemplo": "9558909"
        },
        "version": {
          "desc": "text_sha256 do manifesto.",
          "exemplo": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
        },
        "imageSha": {
          "desc": "sha256 da imagem presente no manifesto.",
          "exemplo": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
        }
      },
      "summary": "Imagem PNG/JPEG do documento comprado, conferida por hash.",
      "retorno": {
        "_texto": "`image/png` ou `image/jpeg`, até 20 MiB por imagem. Não aceita URLs nem caminhos externos."
      },
      "erros": {
        "402": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; os exemplos são gratuitos.",
        "404": "Aquisição não encontrada para a conta autenticada, ou documento/recurso ausente.",
        "409": "Versão do texto alterada; abra o manifesto atual.",
        "502": "Origem indisponível."
      },
      "exemplo": "curl -fsS $ORIGIN/api/documento/9558909/imagens/TEXT_SHA256/IMAGE_SHA256 -o imagem.png",
      "headers": {
        "X-Agent-Pass": {
          "tipo": "string",
          "desc": "Credencial individual do agente, obrigatória junto de X-Editalmd-Avaliacao."
        },
        "X-Editalmd-Avaliacao": {
          "tipo": "string",
          "desc": "evaluation.access_code do premium patrocinado, exclusivo deste documento e agente, com expiração. Use junto de X-Agent-Pass; não é recibo ou compra."
        },
        "X-Editalmd-Acesso": {
          "tipo": "string",
          "desc": "Código privado em acesso.codigo após pagamento de quem não está na conta; até 4096 caracteres. Autoriza este documento ao portador. Compra feita com a sessão da conta não emite código: vale o direito global da conta (cookie HttpOnly), e o do convidado edm_… vale com o token. Recibo público não concede acesso."
        }
      },
      "returns": "`image/png` ou `image/jpeg`, até 20 MiB por imagem. Não aceita URLs nem caminhos externos.",
      "url": "https://editalmd.com/api/documento/:id/imagens/:version/:imageSha",
      "auth_detail": "Sessão da conta com aquisição vinculada, X-Editalmd-Acesso de compra anônima, ou X-Editalmd-Avaliacao junto de X-Agent-Pass para o documento patrocinado. Depois do vínculo da compra, exige conta. Os exemplos são livres."
    },
    {
      "method": "GET",
      "path": "/api/precos",
      "auth": "none",
      "summary": "O preço que ganha para um item parecido, em resumo: quantos preços, a mediana e a faixa. Grátis; o completo é pago.",
      "grupo": "Acervo",
      "desc": "Consulte resultados homologados por descrição do item: os do PNCP, desde 28/10/2026 os que os municípios do Ceará informam ao TCE-CE e, desde 02/11/2026, os do Compras.gov.br para a compra que ainda não está no acervo (`fonte` em cada item). O resumo grátis traz `n`, a mediana e a faixa (p25/p75) dos comparáveis — o mesmo produto do catálogo, na mesma unidade, sem os extremos (`comparacao`) —, os outros grupos que a busca achou (`grupos`: peça `produto` e `unidade` de um deles para trocar), o volume comprado, o preço para a sua `quantidade` (ou a do item da `compra` aberta) e quanto a compra pequena paga a mais, `amostra` (o critério: até 2.000 itens do PNCP, 500 do TCE-CE e 200 do Compras.gov.br mais parecidos pelo texto) e `detalhe`: o endereço (do mesmo grupo), o preço e o tamanho do preço que ganha completo (`GET /api/precos/detalhe`, pago por consulta) — quem vence, quem compra, por UF, por mês, os outros números do resumo e os itens. Aceita também POST, PUT ou PATCH com os mesmos parâmetros em JSON ou formulário; `query`, `termo`, `busca` e `search` valem como `q`, `estado` como `uf`, `limit` como `limite`. Todo 400 traz `exemplo` e `doc`. `Accept: text/html` abre a aba Preços pagos com a consulta.",
      "query": {
        "q": {
          "tipo": "string",
          "desc": "Descrição do item; mínimo 3 letras, até 200.",
          "obrigatorio": true
        },
        "uf": {
          "tipo": "string",
          "desc": "Sigla da UF do órgão comprador."
        },
        "meses": {
          "tipo": "int",
          "desc": "Janela de homologação em meses, 1 a 36.",
          "padrao": 12
        },
        "catmat": {
          "tipo": "string",
          "desc": "Código do item no catálogo do governo, até 64 caracteres."
        },
        "limite": {
          "tipo": "int",
          "desc": "1 a 100 itens.",
          "padrao": 50
        },
        "produto": {
          "tipo": "string",
          "desc": "Produto do catálogo, como em `grupos` (até 80 letras); sem ele, o maior grupo."
        },
        "unidade": {
          "tipo": "string",
          "desc": "Unidade, como em `grupos` (`500 FL`, `1 UN`)."
        },
        "quantidade": {
          "tipo": "number",
          "desc": "Quanto você vai vender, na unidade do grupo: o preço da faixa dessa quantidade."
        },
        "compra": {
          "tipo": "int",
          "desc": "Id da compra no acervo: a quantidade sai do item dela, no grupo da conta. Item em embalagem sem a contagem (`Embalagem FL`) não conta: a unidade não diz quantas folhas."
        }
      },
      "retorno": "PrecosGratis",
      "erros": {
        "400": "Termo curto, ou UF, meses, limite, catmat, produto, unidade, quantidade ou compra fora do contrato — com `exemplo` e `doc`.",
        "502": "Origem indisponível.",
        "503": "Busca demorada: `busca_demorada`, com `Retry-After` — refine o termo ou filtre por UF."
      },
      "exemplo": "curl -s '$ORIGIN/api/precos?q=papel%20a4%20resma&uf=MG&meses=12'",
      "returns": "{ consulta{q,expressao,uf,catmat,produto,unidade,quantidade,compra,meses,desde,limite}, resumo{n,mediana,p25,p75,ultima_homologacao,volume}, amostra{candidatos,limitada,criterio,desde,ate}, comparacao{produto,unidade,comparaveis,no_grupo,validos,sem_produto,criterio}, grupos[{produto,unidade,n}], faixa_da_quantidade{quantidade,origem,faixa,de,ate,n,mediana,p25,p75}, variacao_por_quantidade, detalhe{url,preco_usd,preco_brl,unidades_plano,inclui,previa}, base_legal, pago }",
      "url": "https://editalmd.com/api/precos",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/precos/detalhe",
      "auth": "none",
      "summary": "Relatório completo: quem vence, quem compra, por estado, por mês e os itens. Avulso em reais ou franquia do plano.",
      "grupo": "Acervo",
      "desc": "Os mesmos parâmetros do `/api/precos`. Sem pagamento, 402 com as duas portas (x402 e crédito); pago, o `resumo` inteiro (menor, maior, média, desconto mediano sobre o valor estimado pelo órgão, participação de ME/EPP, fornecedores e compradores distintos), `por_uf`, `por_mes`, `vencedores` (top 10 por itens e valor, com porte), `compradores` (top 10 órgãos), `por_quantidade` (a mediana e a faixa por tamanho da compra) e a amostra de `itens`, cada um com a compra dele — tudo do mesmo grupo comparável (`comparacao`: mesmo produto, mesma unidade, sem os extremos). Pessoa física vencedora sai sem CPF. No crédito, a mesma consulta com o mesmo token não cobra de novo. Resposta privada, sem cache.",
      "query": {
        "q": {
          "tipo": "string",
          "desc": "Descrição do item; mínimo 3 letras, até 200.",
          "obrigatorio": true
        },
        "uf": {
          "tipo": "string",
          "desc": "Sigla da UF do órgão comprador."
        },
        "meses": {
          "tipo": "int",
          "desc": "Janela de homologação em meses, 1 a 36.",
          "padrao": 12
        },
        "catmat": {
          "tipo": "string",
          "desc": "Código do item no catálogo do governo, até 64 caracteres."
        },
        "limite": {
          "tipo": "int",
          "desc": "1 a 100 itens.",
          "padrao": 50
        },
        "produto": {
          "tipo": "string",
          "desc": "Produto do catálogo, como em `grupos` (até 80 letras); sem ele, o maior grupo."
        },
        "unidade": {
          "tipo": "string",
          "desc": "Unidade, como em `grupos` (`500 FL`, `1 UN`)."
        },
        "quantidade": {
          "tipo": "number",
          "desc": "Quanto você vai vender, na unidade do grupo: o preço da faixa dessa quantidade."
        },
        "compra": {
          "tipo": "int",
          "desc": "Id da compra no acervo: a quantidade sai do item dela, no grupo da conta. Item em embalagem sem a contagem (`Embalagem FL`) não conta: a unidade não diz quantas folhas."
        }
      },
      "headers": {
        "X-PAYMENT": {
          "tipo": "string",
          "desc": "Autorização x402 do desafio 402."
        },
        "X-Credito": {
          "tipo": "string",
          "desc": "Token cred_… para descontar do saldo, como alternativa ao x402."
        }
      },
      "retorno": "Precos",
      "erros": {
        "400": "Termo curto, ou UF, meses, limite, catmat, produto, unidade, quantidade ou compra fora do contrato — com `exemplo` e `doc`.",
        "402": "Pagamento necessário ou recusado; anuncia x402 e crédito.",
        "502": "A origem não respondeu (`origem_indisponivel` ou o código dela): nada foi cobrado; repita a consulta.",
        "503": "Detalhe sem preço configurado, ou busca demorada."
      },
      "exemplo": "curl -s '$ORIGIN/api/precos/detalhe?q=papel%20a4%20resma&uf=MG' -H 'X-Credito: cred_…'",
      "returns": "{ consulta{q,expressao,uf,catmat,produto,unidade,quantidade,compra,meses,desde,limite}, estatisticas{total,media,mediana,menor,maior,desvio_padrao}, resumo{n,mediana,p25,p75,menor,maior,media,desconto_mediano,com_referencia,me_epp,valor_total,fornecedores,volume,compradores,ultima_homologacao}, por_uf[{uf,n,mediana,menor,maior,fornecedores,compradores,ultima_homologacao}], por_mes[{mes,n,mediana,menor,maior}], vencedores[{fornecedor_cnpj,pessoa_fisica,fornecedor,porte,itens,valor_total,menor,maior,compradores,ultima_homologacao}], compradores[{orgao_cnpj,orgao,uf,itens,compras,valor_total,fornecedores,ultima_homologacao}], amostra{candidatos,limitada,criterio,desde,ate}, comparacao{produto,unidade,comparaveis,no_grupo,validos,sem_produto,criterio}, grupos[{produto,unidade,n}], faixa_da_quantidade{quantidade,origem,faixa,de,ate,n,mediana,p25,p75}, variacao_por_quantidade, por_quantidade[{faixa,de,ate,n,mediana,p25,p75,menor,maior,volume,fornecedores,compradores,ultima_homologacao}], itens[{compra_id,fonte,item,resultado,pncp,referencia,descricao,unidade,catmat,material_ou_servico,valor_unitario,valor_unitario_estimado,quantidade_homologada,fornecedor,fornecedor_cnpj,pessoa_fisica,fornecedor_porte,orgao,orgao_cnpj,municipio,uf,modalidade,homologado_em,publicado_em,compra_url}], base_legal, pago, pagamento? }",
      "url": "https://editalmd.com/api/precos/detalhe",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/precos/detalhe",
      "auth": "none",
      "summary": "Abrir relatório completo com a franquia do plano, crédito avulso ou pagamento.",
      "grupo": "Acervo",
      "desc": "Conta autenticada usa 25 unidades do plano antes do crédito. Cookie exige CSRF. Repetir a mesma consulta vigente não desconta novamente. Sem franquia suficiente, segue a cobrança avulsa. Os mesmos parâmetros do `/api/precos`. Sem pagamento, 402 com as duas portas (x402 e crédito); pago, o `resumo` inteiro (menor, maior, média, desconto mediano sobre o valor estimado pelo órgão, participação de ME/EPP, fornecedores e compradores distintos), `por_uf`, `por_mes`, `vencedores` (top 10 por itens e valor, com porte), `compradores` (top 10 órgãos), `por_quantidade` (a mediana e a faixa por tamanho da compra) e a amostra de `itens`, cada um com a compra dele — tudo do mesmo grupo comparável (`comparacao`: mesmo produto, mesma unidade, sem os extremos). Pessoa física vencedora sai sem CPF. No crédito, a mesma consulta com o mesmo token não cobra de novo. Resposta privada, sem cache.",
      "query": {
        "q": {
          "tipo": "string",
          "desc": "Descrição do item; mínimo 3 letras, até 200.",
          "obrigatorio": true
        },
        "uf": {
          "tipo": "string",
          "desc": "Sigla da UF do órgão comprador."
        },
        "meses": {
          "tipo": "int",
          "desc": "Janela de homologação em meses, 1 a 36.",
          "padrao": 12
        },
        "catmat": {
          "tipo": "string",
          "desc": "Código do item no catálogo do governo, até 64 caracteres."
        },
        "limite": {
          "tipo": "int",
          "desc": "1 a 100 itens.",
          "padrao": 50
        },
        "produto": {
          "tipo": "string",
          "desc": "Produto do catálogo, como em `grupos` (até 80 letras); sem ele, o maior grupo."
        },
        "unidade": {
          "tipo": "string",
          "desc": "Unidade, como em `grupos` (`500 FL`, `1 UN`)."
        },
        "quantidade": {
          "tipo": "number",
          "desc": "Quanto você vai vender, na unidade do grupo: o preço da faixa dessa quantidade."
        },
        "compra": {
          "tipo": "int",
          "desc": "Id da compra no acervo: a quantidade sai do item dela, no grupo da conta. Item em embalagem sem a contagem (`Embalagem FL`) não conta: a unidade não diz quantas folhas."
        }
      },
      "headers": {
        "X-PAYMENT": {
          "tipo": "string",
          "desc": "Autorização x402 do desafio 402."
        },
        "X-Credito": {
          "tipo": "string",
          "desc": "Token cred_… para descontar do saldo, como alternativa ao x402."
        },
        "X-CSRF-Token": {
          "tipo": "string",
          "desc": "Token do transporte da conta para escrita por cookie."
        }
      },
      "retorno": "Precos",
      "erros": {
        "400": "Termo curto, ou UF, meses, limite, catmat, produto, unidade, quantidade ou compra fora do contrato — com `exemplo` e `doc`.",
        "402": "Pagamento necessário ou recusado; anuncia x402 e crédito.",
        "502": "A origem não respondeu (`origem_indisponivel` ou o código dela): nada foi cobrado; repita a consulta.",
        "503": "Detalhe sem preço configurado, ou busca demorada."
      },
      "exemplo": "curl -X POST '$ORIGIN/api/precos/detalhe?q=papel%20a4%20resma&uf=MG' -H 'Authorization: Bearer mmk_…'",
      "returns": "{ consulta{q,expressao,uf,catmat,produto,unidade,quantidade,compra,meses,desde,limite}, estatisticas{total,media,mediana,menor,maior,desvio_padrao}, resumo{n,mediana,p25,p75,menor,maior,media,desconto_mediano,com_referencia,me_epp,valor_total,fornecedores,volume,compradores,ultima_homologacao}, por_uf[{uf,n,mediana,menor,maior,fornecedores,compradores,ultima_homologacao}], por_mes[{mes,n,mediana,menor,maior}], vencedores[{fornecedor_cnpj,pessoa_fisica,fornecedor,porte,itens,valor_total,menor,maior,compradores,ultima_homologacao}], compradores[{orgao_cnpj,orgao,uf,itens,compras,valor_total,fornecedores,ultima_homologacao}], amostra{candidatos,limitada,criterio,desde,ate}, comparacao{produto,unidade,comparaveis,no_grupo,validos,sem_produto,criterio}, grupos[{produto,unidade,n}], faixa_da_quantidade{quantidade,origem,faixa,de,ate,n,mediana,p25,p75}, variacao_por_quantidade, por_quantidade[{faixa,de,ate,n,mediana,p25,p75,menor,maior,volume,fornecedores,compradores,ultima_homologacao}], itens[{compra_id,fonte,item,resultado,pncp,referencia,descricao,unidade,catmat,material_ou_servico,valor_unitario,valor_unitario_estimado,quantidade_homologada,fornecedor,fornecedor_cnpj,pessoa_fisica,fornecedor_porte,orgao,orgao_cnpj,municipio,uf,modalidade,homologado_em,publicado_em,compra_url}], base_legal, pago, pagamento? }",
      "url": "https://editalmd.com/api/precos/detalhe",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "auth": "credito",
      "method": "GET",
      "path": "/api/x402/precos",
      "grupo": "Acervo",
      "summary": "O preço que ganha resumido para o agente, pago por chamada, sem conta: o resumo completo e até 10 itens.",
      "desc": "Um quinto do relatório de `GET /api/precos/detalhe`, com o mesmo preço por parte: o resumo grátis, o resumo completo (menor, maior, média, desconto e ME/EPP) e até 10 itens, vendido por chamada ao agente, sem conta, sem franquia e sem plano. Quem vence, quem compra e a distribuição por estado, mês e tamanho ficam no relatório completo (`detalhe`), pelo preço da pessoa, com x402 ou crédito. O pedido sem pagamento recebe o 402 com o preço; o pago recebe a resposta na mesma chamada, com o pagamento em `cobranca`. A consulta vem antes da liquidação: o termo recusado e a origem fora do ar voltam com o erro, sem cobrar.",
      "query": {
        "q": {
          "tipo": "string",
          "desc": "Descrição do item; mínimo 3 letras, até 200.",
          "obrigatorio": true,
          "exemplo": "papel a4 resma"
        },
        "uf": {
          "tipo": "string",
          "desc": "Sigla da UF do órgão comprador.",
          "exemplo": "MG"
        },
        "meses": {
          "tipo": "int",
          "desc": "Janela de homologação em meses, 1 a 36.",
          "padrao": 12
        },
        "catmat": {
          "tipo": "string",
          "desc": "Código do item no catálogo do governo, até 64 caracteres."
        },
        "limite": {
          "tipo": "int",
          "desc": "1 a 100 itens.",
          "padrao": 50
        },
        "produto": {
          "tipo": "string",
          "desc": "Produto do catálogo, como em `grupos` (até 80 letras); sem ele, o maior grupo."
        },
        "unidade": {
          "tipo": "string",
          "desc": "Unidade, como em `grupos` (`500 FL`, `1 UN`)."
        },
        "quantidade": {
          "tipo": "number",
          "desc": "Quanto você vai vender, na unidade do grupo: o preço da faixa dessa quantidade."
        },
        "compra": {
          "tipo": "int",
          "desc": "Id da compra no acervo: a quantidade sai do item dela, no grupo da conta. Item em embalagem sem a contagem (`Embalagem FL`) não conta: a unidade não diz quantas folhas."
        }
      },
      "retorno": "PrecosAvulso",
      "exemploRetorno": {
        "consulta": {
          "q": "papel a4 resma",
          "expressao": "+papel* +resma*",
          "uf": "MG",
          "catmat": null,
          "produto": null,
          "unidade": null,
          "compra": null,
          "quantidade": null,
          "meses": 12,
          "desde": "2025-10-30",
          "limite": 50
        },
        "resumo": {
          "n": 3,
          "mediana": 24.97,
          "p25": 22.45,
          "p75": 25.1,
          "menor": 22.45,
          "maior": 25.1,
          "media": 24.1733333333,
          "desconto_mediano": 0.0935,
          "com_referencia": 3,
          "me_epp": 1,
          "valor_total": 306800,
          "volume": 12500,
          "fornecedores": 3,
          "compradores": 2,
          "ultima_homologacao": "2026-08-26"
        },
        "amostra": {
          "candidatos": 703,
          "limitada": true,
          "criterio": "até 2000 itens do PNCP, 500 do TCE-CE e 200 do Compras.gov.br mais parecidos pelo texto (FULLTEXT na descrição do item), com resultado homologado válido no período; a conta usa só os comparáveis (`comparacao`)",
          "desde": "2025-10-30",
          "ate": "2026-08-26"
        },
        "comparacao": {
          "produto": "Papel Para Impressão Formatado",
          "unidade": "500 FL",
          "comparaveis": 3,
          "no_grupo": 3,
          "validos": 7,
          "sem_produto": 0,
          "criterio": "mesmo produto do catálogo e mesma unidade de fornecimento; fora os preços abaixo de 50% ou acima de 150% da mediana"
        },
        "grupos": [
          {
            "produto": "Papel Para Impressão Formatado",
            "unidade": "500 FL",
            "n": 3
          }
        ],
        "faixa_da_quantidade": null,
        "variacao_por_quantidade": null,
        "detalhe": {
          "url": "https://editalmd.com/api/precos/detalhe?q=papel+a4+resma&meses=12&limite=50&uf=MG&produto=Papel+Para+Impress%C3%A3o+Formatado&unidade=500+FL",
          "preco_usd": "$0.50",
          "preco_brl": 2.75,
          "unidades_plano": 25,
          "inclui": [
            "resumo completo: menor, maior, média, desconto sobre a referência do órgão e participação de ME/EPP",
            "vencedores: quem ganhou, com CNPJ, porte, itens e valor",
            "compradores: quais órgãos compraram, com itens, compras e valor",
            "por_uf e por_mes: a mediana e a faixa por estado e por mês",
            "por_quantidade: a mediana e a faixa por tamanho da compra, com o volume de cada faixa",
            "itens: cada resultado homologado, com a compra dele"
          ],
          "previa": {
            "fornecedores": 3,
            "compradores": 2,
            "estados": 1,
            "itens": 3
          }
        },
        "itens": [
          {
            "compra_id": 25791797,
            "item": 85,
            "resultado": 1,
            "pncp": "00394452000103-1-015331/2026",
            "referencia": "PNCP 00394452000103-1-015331/2026 · item 85",
            "descricao": "Papel Para Impressão Formatado tipo: sulfite/apergaminhado/ofício, tamanho (c x l): 297 x 210, gramatura: 75, cor: branco, característica adicional: ph alcalino Papel para impressão\nformatado; Papel A4, alcalino,\n297 mm x 210 mm, 75 g/m²,\nresma com 500 folhas brancas",
            "unidade": "Embalagem 500 FL",
            "catmat": null,
            "material_ou_servico": "M",
            "valor_unitario": 24.97,
            "valor_unitario_estimado": 27.69,
            "quantidade_homologada": 2500,
            "fornecedor": "BRS SOLUCOES INTEGRADAS LTDA",
            "fornecedor_cnpj": "36193935000189",
            "pessoa_fisica": false,
            "fornecedor_porte": "ME",
            "orgao": "COMANDO DO EXERCITO",
            "orgao_cnpj": "00394452000103",
            "municipio": "Três Corações",
            "uf": "MG",
            "modalidade": "Pregão - Eletrônico",
            "homologado_em": "2026-08-26",
            "publicado_em": "2026-07-31",
            "compra_url": "https://editalmd.com/api/compra/25791797"
          }
        ],
        "base_legal": "Lei 14.133/2021, art. 23, § 1º, II; IN SEGES/ME 65/2021, art. 5º, II — contratações similares homologadas no PNCP.",
        "pago": true
      },
      "erros": {
        "400": "Pago sem `q` (`missing_input`), ou termo curto, UF, meses, limite, catmat, produto, unidade ou quantidade fora do contrato, com `example`. Não cobra.",
        "401": "Chave recusada (`invalid_api_key`), token OAuth recusado (`invalid_token`), crédito recusado (`credito_invalido`), crédito de teste fora do dev (`credito_simulado`) ou recuperação sem autenticação da carteira (`wallet_proof_required`). A primeira compra x402 não exige conta.",
        "402": "Sem pagamento: `accepts` (x402, USDC na Base) com o preço desta chamada, no mínimo US$ 0,01; `credito.preco_desta_chamada`, o preço menor com o crédito pré-pago; e `pacotes` (as recargas de crédito e quantas chamadas cada uma paga). Com o crédito sem saldo, `saldo_insuficiente`.",
        "409": "Pagamento em processamento, pedido diferente do original ou valor já recuperado no saldo. Não assine outra autorização para repetir a compra.",
        "410": "O prazo de 24 horas para recuperar a resposta acabou. O registro financeiro permanece; repetir a prova não cobra outra vez.",
        "502": "Origem indisponível. Não cobra.",
        "503": "Busca demorada (`busca_demorada`), com `Retry-After`: refine o termo ou filtre por UF. Não cobra."
      },
      "exemplo": "curl -s -i '$ORIGIN/api/x402/precos?q=papel%20a4%20resma&uf=MG'",
      "headers": {
        "authorization": {
          "tipo": "string",
          "obrigatorio": false,
          "desc": "`Bearer mmk_…` (chave de API) ou `Bearer mmo_…` (OAuth): a chamada paga usa o saldo da conta, sem outro cabeçalho. Sem conta, `Bearer cred_…` usa o crédito comprado em `POST /api/credito`."
        },
        "x-api-key": {
          "tipo": "string",
          "obrigatorio": false,
          "desc": "A chave de API `mmk_…` deste produto. Identifica a conta e autoriza usar o saldo na chamada paga."
        },
        "payment-signature": {
          "tipo": "string",
          "obrigatorio": false,
          "desc": "A prova x402 assinada (base64): `PAYMENT-SIGNATURE` (v2) ou `X-PAYMENT` (v1)."
        },
        "x-wallet-token": {
          "tipo": "string",
          "obrigatorio": false,
          "desc": "Para recuperar uma resposta x402 por até 24 horas, repita o mesmo pedido e a mesma prova. Envie aqui a credencial `mmw_…` da carteira pagadora, emitida por `/api/auth/wallet/agent/start` e `/api/auth/wallet/agent/token`. Não há nova cobrança."
        }
      },
      "agent_value": {
        "idioma": "pt",
        "en": {
          "when": "What prices have public buyers paid for this item?",
          "result": "The complete price summary and up to ten items from the covered data, in one account-free response.",
          "replaces": "Collecting procurement items and calculating the returned price summary.",
          "free": "Inspect the free price summary and confirm that the search term identifies comparable items.",
          "paid": "This per-call route uses x402 or credit. The full detail report is a different purchase with broader breakdowns.",
          "limits": "A text match does not establish equivalent specifications, delivery conditions or a valid bid price. Check source dates and the matched items.",
          "alternative": "The free summary answers the question or your task requires details outside this compact report."
        },
        "pt": {
          "when": "Que preços as compras públicas registram para este item?",
          "result": "Resumo completo de preços e até dez itens dos dados cobertos, em uma resposta sem conta.",
          "replaces": "Coleta de itens de compras e cálculo do resumo de preços devolvido.",
          "free": "Confira o resumo gratuito e confirme que o termo identifica itens comparáveis.",
          "paid": "A rota por chamada aceita x402 ou crédito. O relatório de detalhe é outra compra, com recortes mais amplos.",
          "limits": "Texto parecido não prova especificação, entrega ou preço de proposta equivalente. Confira datas e itens encontrados.",
          "alternative": "O resumo gratuito resolve ou a tarefa exige detalhes fora deste relatório compacto."
        }
      },
      "returns": "{ consulta{q,expressao,uf,catmat,produto,unidade,quantidade,compra,meses,desde,limite}, resumo{n,mediana,p25,p75,menor,maior,media,desconto_mediano,com_referencia,me_epp,valor_total,fornecedores,volume,compradores,ultima_homologacao}, amostra{candidatos,limitada,criterio,desde,ate}, comparacao{produto,unidade,comparaveis,no_grupo,validos,sem_produto,criterio}, grupos[{produto,unidade,n}], faixa_da_quantidade{quantidade,origem,faixa,de,ate,n,mediana,p25,p75}, variacao_por_quantidade, detalhe{url,preco_usd,preco_brl,unidades_plano,inclui,previa}, base_legal, pago, itens[{compra_id,fonte,item,resultado,pncp,referencia,descricao,unidade,catmat,material_ou_servico,valor_unitario,valor_unitario_estimado,quantidade_homologada,fornecedor,fornecedor_cnpj,pessoa_fisica,fornecedor_porte,orgao,orgao_cnpj,municipio,uf,modalidade,homologado_em,publicado_em,compra_url}], cobranca{via,preco_usd,repetido,saldo_usd?} }",
      "url": "https://editalmd.com/api/x402/precos",
      "auth_detail": "Token de crédito em `Authorization: Bearer cred_…` (ou `X-Credito`). Para saldo recuperado de x402, use a credencial de carteira `mmw_…` em Bearer ou `X-Wallet-Token`, emitida por `/api/auth/wallet/agent/start` e `/api/auth/wallet/agent/token`."
    },
    {
      "method": "GET",
      "path": "/api/servicos",
      "auth": "none",
      "summary": "Os serviços do produto com preço fechado em reais e como pagar.",
      "desc": "Cada serviço traz o que entrega (`inclui`), o limite dele (`aviso`), o preço em centavos de reais, o Pix copia e cola do preço e o endereço do pedido. `pagamento` diz como pagar: `liberacao: automatica` (Pix, cartão ou boleto pelo gateway; pago, o pedido segue sozinho) ou `manual` (Pix para a chave, com o comprovante conferido à mão). A resposta vem por e-mail. `lingua=pt|en` escolhe a língua do texto (padrão: a do pedido).",
      "grupo": "Serviços",
      "query": {
        "lingua": {
          "tipo": "string",
          "desc": "`pt` ou `en`; sem ela, a língua do pedido."
        }
      },
      "retorno": {
        "servicos": {
          "tipo": "object[]",
          "desc": "`id`, `nome`, `resumo`, `inclui[]`, `aviso`, `preco` (`moeda`, `centavos`, `texto`), `copia_e_cola` (o Pix copia e cola do preço, o mesmo texto do QR) e `pedido`."
        },
        "creditos": {
          "tipo": "object[]",
          "desc": "Os pacotes de crédito da casa em reais, pagos pelo mesmo Pix (`POST /api/credito/pix`): `usd`, `preco` (`moeda`, `centavos`, `texto`) e `copia_e_cola`."
        },
        "pagamento": {
          "tipo": "object",
          "desc": "Automático: `metodo: asaas`, `liberacao: automatica`, `formas` (`pix`, `cartao_boleto`) e `precisa_documento` (o CPF ou CNPJ de quem paga, só na primeira compra da conta). Manual: `metodo: pix`, a `chave`, `liberacao: manual` e o `comprovante` aceito."
        },
        "como": {
          "tipo": "string",
          "desc": "Como pedir, em uma frase."
        }
      },
      "exemplo": "curl -s '$ORIGIN/api/servicos?lingua=pt'",
      "returns": "{ servicos, creditos, pagamento, como }",
      "url": "https://editalmd.com/api/servicos",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/servicos/:id/pedido",
      "auth": "none",
      "summary": "Pede um serviço: em JSON, a cobrança que libera sozinha (`liberacao: automatica`); em multipart, o Pix com comprovante.",
      "desc": "Automático (JSON): `email` e, quando `precisa_documento`, `documento` e `nome` de quem paga; `forma` `pix` (o padrão) ou `cartao_boleto`. A resposta (201) é a cobrança: `id`, `estado: pendente`, `servico`, `centavos`, o `pix` (`copia_e_cola`, `imagem`) ou `pagamento_em` (a página de cartão e boleto) e `estado_em` (`GET /api/credito/asaas/:id`, que vira `pago`). Pago, o pedido vai sozinho a quem atende. Manual (multipart): faça o Pix do preço para a chave de `GET /api/servicos` e mande o comprovante. Nos dois, `nome`, `telefone`, `empresa` (empresa ou CNPJ), `mensagem` (o que precisa, até 2.000 caracteres), `contexto` (de onde pediu, até 300), `pagina` (a página aberta, até 2.000) e `navegador_id` (UUID do navegador) vão junto. O pedido fica registrado com tudo o que chegou — o comprovante inclusive —, com a conta logada, a rede e o navegador de quem pediu, e vai ao e-mail de quem atende, que confere o Pix e responde no e-mail informado.",
      "grupo": "Serviços",
      "params": {
        "id": {
          "desc": "O `id` do serviço no catálogo.",
          "exemplo": "analise-assistida"
        }
      },
      "retorno": {
        "id": {
          "tipo": "string",
          "desc": "O número do pedido (32 hex), para citar ao falar conosco."
        },
        "estado": {
          "tipo": "string",
          "desc": "`recebido` (manual) ou `pendente` (automático, até o pagamento cair)."
        },
        "servico": {
          "tipo": "object",
          "desc": "`id` e `nome` do serviço pedido."
        },
        "valor": {
          "tipo": "string",
          "desc": "O preço do serviço, em reais."
        },
        "aviso": {
          "tipo": "string",
          "desc": "O que acontece agora."
        }
      },
      "erros": {
        "400": "Sem comprovante ou sem e-mail válido; no automático, documento inválido, ou JSON onde o app só aceita o comprovante (`pedido_manual`).",
        "404": "Serviço desconhecido.",
        "413": "Comprovante acima de 2 MB.",
        "415": "Comprovante que não é foto (JPEG, PNG, WebP) nem PDF.",
        "429": "A rede já mandou os pedidos do dia.",
        "502": "O gateway não gerou a cobrança (automático), ou o e-mail não saiu (manual: o pedido fica registrado como `falhou`); mande de novo.",
        "503": "Serviço sem preço neste app, e-mail ou banco indisponível, ou pedidos demais no dia."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/servicos/analise-assistida/pedido -H 'content-type: application/json' -d '{\"email\":\"voce@empresa.com.br\",\"documento\":\"CPF ou CNPJ\",\"nome\":\"Seu nome\"}'",
      "returns": "{ id, estado, servico, valor, aviso }",
      "url": "https://editalmd.com/api/servicos/:id/pedido",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/alertas/previa",
      "auth": "none",
      "grupo": "Acompanhar",
      "summary": "Testa termos e filtros ou sugere termos pelo CNPJ, sem criar alerta.",
      "corpo": {
        "termos": {
          "tipo": "string",
          "desc": "3 a 200 caracteres; obrigatório sem CNPJ e sem `filtros.cnaes`."
        },
        "cnpj": {
          "tipo": "string",
          "desc": "CNPJ para sugerir até 8 famílias de termos, sem ativá-las."
        },
        "uf": {
          "tipo": "string",
          "desc": "Sigla da UF."
        },
        "filtros": {
          "tipo": "FiltrosInteresse",
          "desc": "Recorte adicional: modalidades, esferas, municípios, exclusões, valores, propostas abertas, só com disputa, só registro de preços e CNAEs. PATCH substitui o recorte inteiro; {} limpa."
        }
      },
      "body": {
        "termos": "uniforme escolar",
        "uf": "GO",
        "filtros": {
          "modalidades": [
            6
          ]
        }
      },
      "retorno": {
        "sugestoes": {
          "tipo": "object[]",
          "desc": "Família, nome, termos editáveis e CNAEs; só no modo CNPJ."
        },
        "itens": {
          "tipo": "Compra[]",
          "desc": "Até 20 compras dos últimos 7 dias; cada uma tem url para a ficha."
        },
        "aviso": {
          "tipo": "string",
          "desc": "Limites da amostra ou da sugestão."
        },
        "periodo_dias": {
          "tipo": "int",
          "desc": "7, só na amostra por termos.",
          "opcional": true
        },
        "limite": {
          "tipo": "int",
          "desc": "20, só na amostra por termos.",
          "opcional": true
        }
      },
      "erros": {
        "400": "Termos, CNPJ, UF ou filtros inválidos.",
        "404": "Empresa não encontrada.",
        "503": "Origem indisponível."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/alertas/previa -H 'content-type: application/json' -d '{\"termos\":\"uniforme escolar\"}'",
      "returns": "{ sugestoes, itens[{id,pncp,objeto,uf,modalidade,situacao,orgao,unidade,valor_estimado,publicado_em,informacao_complementar,processo,abertura_proposta,encerramento_proposta,amparo_legal,amparo_legal_codigo,modalidade_id,situacao_id,municipio,municipio_ibge,orgao_cnpj,ano_compra,sequencial_compra,atualizado_em,prazos,pncp_url,markdown_url,compra_url,resultado?}], aviso, periodo_dias?, limite? }",
      "url": "https://editalmd.com/api/alertas/previa",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/salvas",
      "auth": "owner",
      "grupo": "Acompanhar",
      "summary": "Lista até 200 licitações salvas pelo dono, gratuitamente.",
      "retorno": {
        "itens": {
          "tipo": "CompraSalva[]",
          "desc": "Mais recentes primeiro; retrato obtido ao salvar."
        },
        "limite": {
          "tipo": "int",
          "desc": "200 por dono."
        }
      },
      "erros": {
        "401": "Token de dono ausente ou inválido.",
        "503": "Banco indisponível."
      },
      "exemplo": "curl -s $ORIGIN/api/salvas -H \"Authorization: Bearer $EDM\"",
      "returns": "{ itens[{compra_id,compra,salvo_em,url}], limite }",
      "url": "https://editalmd.com/api/salvas",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "GET",
      "path": "/api/salvas/:id",
      "auth": "owner",
      "grupo": "Acompanhar",
      "summary": "Consulta uma licitação salva pelo dono.",
      "desc": "Salvar não cria vigia nem notificação. O cliente fornece somente o ID; o retrato vem do acervo.",
      "params": {
        "id": {
          "desc": "Identificador da compra no acervo.",
          "exemplo": "42"
        }
      },
      "retorno": {
        "salva": {
          "tipo": "CompraSalva",
          "desc": "Licitação salva."
        }
      },
      "erros": {
        "401": "Token de dono ausente ou inválido.",
        "404": "Compra não encontrada.",
        "409": "Limite de 200 salvas atingido.",
        "503": "Banco, origem ou orçamento diário indisponível."
      },
      "exemplo": "curl -s -XGET $ORIGIN/api/salvas/42 -H \"Authorization: Bearer $EDM\"",
      "returns": "{ salva{compra_id,compra,salvo_em,url} }",
      "url": "https://editalmd.com/api/salvas/:id",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "PUT",
      "path": "/api/salvas/:id",
      "auth": "owner",
      "grupo": "Acompanhar",
      "summary": "Salva a licitação gratuitamente; repetir não duplica.",
      "desc": "Salvar não cria vigia nem notificação. O cliente fornece somente o ID; o retrato vem do acervo.",
      "params": {
        "id": {
          "desc": "Identificador da compra no acervo.",
          "exemplo": "42"
        }
      },
      "retorno": {
        "salva": {
          "tipo": "CompraSalva",
          "desc": "Licitação salva."
        }
      },
      "erros": {
        "401": "Token de dono ausente ou inválido.",
        "404": "Compra não encontrada.",
        "409": "Limite de 200 salvas atingido.",
        "503": "Banco, origem ou orçamento diário indisponível."
      },
      "exemplo": "curl -s -XPUT $ORIGIN/api/salvas/42 -H \"Authorization: Bearer $EDM\"",
      "returns": "{ salva{compra_id,compra,salvo_em,url} }",
      "url": "https://editalmd.com/api/salvas/:id",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "DELETE",
      "path": "/api/salvas/:id",
      "auth": "owner",
      "grupo": "Acompanhar",
      "summary": "Remove a licitação da lista pessoal; repetir é seguro.",
      "desc": "Salvar não cria vigia nem notificação. O cliente fornece somente o ID; o retrato vem do acervo.",
      "params": {
        "id": {
          "desc": "Identificador da compra no acervo.",
          "exemplo": "42"
        }
      },
      "retorno": {
        "_texto": "204 sem corpo."
      },
      "erros": {
        "401": "Token de dono ausente ou inválido.",
        "404": "Compra não encontrada.",
        "409": "Limite de 200 salvas atingido.",
        "503": "Banco, origem ou orçamento diário indisponível."
      },
      "exemplo": "curl -s -XDELETE $ORIGIN/api/salvas/42 -H \"Authorization: Bearer $EDM\"",
      "returns": "204 sem corpo.",
      "url": "https://editalmd.com/api/salvas/:id",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "POST",
      "path": "/api/alertas",
      "auth": "owner",
      "summary": "Cria alertas de compra nova: por termos do objeto e UF, ou pelo CNPJ da empresa (um alerta por família de atividade), entregues por pull, webhook ou e-mail.",
      "grupo": "Acompanhar",
      "desc": "Crie por termos ou por CNPJ. Espaço exige todos os grupos; `|` aceita alternativas no grupo. Por CNPJ, cada família de atividade conhecida gera um alerta, até `max_familias`. Atividade sem família fica na resposta e não gera alerta. O primeiro alerta ativo é grátis; os demais valem 30 dias e usam plano, crédito ou x402. O cron confere a cada 30 minutos. E-mail exige sessão e `EMAIL_ALERTAS=1`. Sem destinatários explícitos, o aviso usa o e-mail verificado da conta. No webhook e no e-mail, o alerta também entrega a licitação nova fora do PNCP que ainda vai abrir, informada ao tribunal de contas do estado (hoje, o LicitaCon do TCE-RS e os dados abertos do TCE-PE). O webhook a envia em `fora_do_pncp`. O alerta com `disputa`, `srp`, `esferas` ou `cnaes` não recebe essas licitações, porque a fonte não tem esses dados. O histórico do alerta lista só as compras do PNCP.",
      "corpo": {
        "nome": {
          "tipo": "string",
          "desc": "Alert name, up to 100 characters."
        },
        "organizacao_id": {
          "tipo": "string",
          "nulo": true,
          "desc": "Organization from `GET /api/me/empresas`. Membership and MFA are checked. Null removes the label. This does not share alert ownership."
        },
        "destinatarios": {
          "tipo": "DestinatariosAlerta",
          "desc": "Email recipients: `para`, `cc` and `bcc` arrays. Up to 10 distinct addresses in total. An empty `para` list uses the account email. PATCH replaces all three lists. BCC is hidden from other recipients."
        },
        "resultados": {
          "tipo": "bool",
          "desc": "Also deliver the result of each matching purchase when PNCP publishes it, on the same channel: the purchase comes back once with `resultado` (awarded value, items, date and the three largest winners). It starts when turned on, without past results. `abertas` does not apply to results."
        },
        "termos": {
          "tipo": "string",
          "desc": "Palavras do objeto da compra (3 a 200 letras); espaço = todas, `|` = qualquer uma do grupo. Obrigatório sem `cnpj`; ignorado com `cnpj`."
        },
        "cnpj": {
          "tipo": "string",
          "desc": "CNPJ da empresa (14 dígitos, com ou sem pontuação): os termos saem das atividades (CNAE) dela, um alerta por família."
        },
        "max_familias": {
          "tipo": "int",
          "desc": "Só com `cnpj`: quantas famílias viram alerta, principal primeiro (1 a 8).",
          "padrao": 8
        },
        "uf": {
          "tipo": "string",
          "desc": "Sigla da UF para restringir; sem UF vale o Brasil inteiro."
        },
        "filtros": {
          "tipo": "FiltrosInteresse",
          "desc": "Recorte adicional: modalidades, esferas, municípios, exclusões, valores, propostas abertas, só com disputa, só registro de preços e CNAEs. PATCH substitui o recorte inteiro; {} limpa."
        },
        "canal": {
          "tipo": "string",
          "desc": "`pull`, `webhook` ou `email`. E-mail exige sessão; sem destinatários explícitos, usa o e-mail da conta.",
          "valores": [
            "pull",
            "webhook",
            "email"
          ],
          "padrao": "pull"
        },
        "destino": {
          "tipo": "string",
          "desc": "URL https pública na porta 443, sem credencial (webhook). Ignorado no pull e no e-mail."
        }
      },
      "body": {
        "termos": "uniforme|fardamento escolar",
        "uf": "GO",
        "canal": "pull"
      },
      "retorno": {
        "alerta": {
          "tipo": "Alerta",
          "desc": "O alerta criado (modo termos).",
          "opcional": true
        },
        "alertas": {
          "tipo": "Alerta[]",
          "desc": "Os alertas criados, um por família (modo CNPJ).",
          "opcional": true
        },
        "empresa": {
          "tipo": "Empresa",
          "desc": "A ficha resumida e cada CNAE com a família que o acionou (modo CNPJ).",
          "opcional": true
        },
        "nao_criados": {
          "tipo": "FamiliaNaoCriada[]",
          "desc": "Famílias que ficaram de fora por `max_familias` (modo CNPJ).",
          "opcional": true
        },
        "pagamento": {
          "tipo": "object",
          "desc": "`via` (franquia, credito ou x402), `preco_usd`, `pago_ate` e, no modo CNPJ, `alertas_pagos` e `preco_unitario_usd`."
        }
      },
      "erros": {
        "400": "Termos, CNPJ, UF, canal ou destino inválidos.",
        "401": "Sem token de convidado nem sessão da conta, token desconhecido, credencial da carteira recusada (`invalid_wallet_token`), ou `session_ended` (cookie de sessão vencida: entre de novo).",
        "402": "Acima da franquia sem pagamento — `accepts[]` do x402 e o caminho do crédito.",
        "403": "`email_exige_conta`: canal e-mail sem a sessão da conta (convidado não tem e-mail); ou `invalid_origin`/`invalid_csrf` na escrita com o cookie da conta.",
        "404": "CNPJ não encontrado na base consultada.",
        "422": "CNPJ sem nenhuma atividade no dicionário: crie por termos (a resposta traz os CNAEs).",
        "502": "`pago_nao_registrado`: o pagamento entrou e a gravação da compra falhou — guarde o `recibo`; o alerta não foi criado.",
        "503": "Canal e-mail desligado, ou a consulta ao CNPJ indisponível agora (`retry_after`)."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/alertas -H \"Authorization: Bearer $EDM\" -H 'content-type: application/json' -d '{\"cnpj\":\"00.394.460/0001-41\",\"uf\":\"GO\",\"canal\":\"pull\"}'",
      "returns": "{ alerta?{id,nome,organizacao,destinatarios,resultados,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url,compras_total}, alertas?[{id,nome,organizacao,destinatarios,resultados,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url,compras_total}], empresa?{cnpj,cnpj_formatado,razao_social,nome_fantasia,situacao,uf,municipio,cnaes}, nao_criados?[{familia,nome,termos,cnaes,motivo}], pagamento }",
      "url": "https://editalmd.com/api/alertas",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "GET",
      "path": "/api/alertas",
      "auth": "owner",
      "summary": "Lista os alertas deste dono, os mais novos primeiro.",
      "grupo": "Acompanhar",
      "retorno": {
        "itens": {
          "tipo": "Alerta[]",
          "desc": "Até 50 alertas do dono."
        },
        "total": {
          "tipo": "int",
          "desc": "Total de alertas deste dono, incluindo pausados; não se limita aos 50 itens da resposta."
        },
        "franquia_alertas": {
          "tipo": "int",
          "desc": "Quantos alertas ativos são grátis."
        }
      },
      "erros": {
        "401": "Sem token de convidado nem sessão da conta, token desconhecido, credencial da carteira recusada (`invalid_wallet_token`), ou `session_ended` (cookie de sessão vencida: entre de novo).",
        "403": "`invalid_origin` / `invalid_csrf`: escrita com o cookie da conta fora da mesma origem ou sem X-CSRF-Token.",
        "503": "`conta_indisponivel`: conta fora do ar agora; nada muda."
      },
      "exemplo": "curl -s $ORIGIN/api/alertas -H \"Authorization: Bearer $EDM\"",
      "returns": "{ itens[{id,nome,organizacao,destinatarios,resultados,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url,compras_total}], total, franquia_alertas }",
      "url": "https://editalmd.com/api/alertas",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "GET",
      "path": "/api/alertas/:id",
      "auth": "owner",
      "summary": "Um alerta do dono, com os filtros e a data da última verificação.",
      "grupo": "Acompanhar",
      "params": {
        "id": {
          "desc": "Identificador do alerta, devolvido na criação.",
          "exemplo": "9f3c…"
        }
      },
      "retorno": {
        "alerta": {
          "tipo": "Alerta",
          "desc": "O alerta."
        }
      },
      "erros": {
        "401": "Sem token de convidado nem sessão da conta, token desconhecido, credencial da carteira recusada (`invalid_wallet_token`), ou `session_ended` (cookie de sessão vencida: entre de novo).",
        "403": "`invalid_origin` / `invalid_csrf`: escrita com o cookie da conta fora da mesma origem ou sem X-CSRF-Token.",
        "404": "Alerta inexistente ou de outro dono.",
        "503": "`conta_indisponivel`: conta fora do ar agora; nada muda."
      },
      "exemplo": "curl -s $ORIGIN/api/alertas/$ID -H \"Authorization: Bearer $EDM\"",
      "returns": "{ alerta{id,nome,organizacao,destinatarios,resultados,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url,compras_total} }",
      "url": "https://editalmd.com/api/alertas/:id",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "GET",
      "path": "/api/alertas/:id/compras",
      "auth": "owner",
      "summary": "As compras que já casaram com o alerta — é o canal pull, e a prova do que foi entregue.",
      "grupo": "Acompanhar",
      "params": {
        "id": {
          "desc": "Identificador do alerta.",
          "exemplo": "9f3c…"
        }
      },
      "query": {
        "limite": {
          "tipo": "int",
          "desc": "1 a 100 (padrão 50), IDs mais altos primeiro."
        },
        "antes_compra": {
          "tipo": "int",
          "desc": "Use proximo_antes da página anterior para continuar."
        }
      },
      "retorno": {
        "alerta": {
          "tipo": "Alerta",
          "desc": "O alerta."
        },
        "itens": {
          "tipo": "AlertaCompra[]",
          "desc": "Compras casadas, com o status da entrega."
        },
        "limite": {
          "tipo": "int",
          "desc": "Teto aplicado."
        },
        "proximo_antes": {
          "tipo": "int",
          "desc": "Cursor da próxima página; nulo no fim.",
          "nulo": true
        }
      },
      "erros": {
        "401": "Sem token de convidado nem sessão da conta, token desconhecido, credencial da carteira recusada (`invalid_wallet_token`), ou `session_ended` (cookie de sessão vencida: entre de novo).",
        "403": "`invalid_origin` / `invalid_csrf`: escrita com o cookie da conta fora da mesma origem ou sem X-CSRF-Token.",
        "404": "Alerta inexistente ou de outro dono.",
        "503": "`conta_indisponivel`: conta fora do ar agora; nada muda."
      },
      "exemplo": "curl -s \"$ORIGIN/api/alertas/$ID/compras?limite=20\" -H \"Authorization: Bearer $EDM\"",
      "returns": "{ alerta{id,nome,organizacao,destinatarios,resultados,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url,compras_total}, itens[{compra_id,status,visto_em,compra}], limite, proximo_antes }",
      "url": "https://editalmd.com/api/alertas/:id/compras",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "PATCH",
      "path": "/api/alertas/:id",
      "auth": "owner",
      "summary": "Pausa, reativa ou muda termos, UF, filtros, canal e destino de um alerta.",
      "grupo": "Acompanhar",
      "params": {
        "id": {
          "desc": "Identificador do alerta.",
          "exemplo": "9f3c…"
        }
      },
      "corpo": {
        "nome": {
          "tipo": "string",
          "desc": "Alert name, up to 100 characters."
        },
        "organizacao_id": {
          "tipo": "string",
          "nulo": true,
          "desc": "Organization from `GET /api/me/empresas`. Membership and MFA are checked. Null removes the label. This does not share alert ownership."
        },
        "destinatarios": {
          "tipo": "DestinatariosAlerta",
          "desc": "Email recipients: `para`, `cc` and `bcc` arrays. Up to 10 distinct addresses in total. An empty `para` list uses the account email. PATCH replaces all three lists. BCC is hidden from other recipients."
        },
        "resultados": {
          "tipo": "bool",
          "desc": "Also deliver the result of each matching purchase when PNCP publishes it, on the same channel: the purchase comes back once with `resultado` (awarded value, items, date and the three largest winners). It starts when turned on, without past results. `abertas` does not apply to results."
        },
        "ativo": {
          "tipo": "bool",
          "desc": "`false` pausa sem apagar; `true` reativa."
        },
        "termos": {
          "tipo": "string",
          "desc": "Novos termos do objeto (3 a 200 letras; `|` = qualquer uma do grupo)."
        },
        "uf": {
          "tipo": "string",
          "desc": "Nova UF; vazio tira a restrição."
        },
        "filtros": {
          "tipo": "FiltrosInteresse",
          "desc": "Recorte adicional: modalidades, esferas, municípios, exclusões, valores, propostas abertas, só com disputa, só registro de preços e CNAEs. PATCH substitui o recorte inteiro; {} limpa."
        },
        "canal": {
          "tipo": "string",
          "desc": "`pull`, `webhook` ou `email`. E-mail exige sessão; sem destinatários explícitos, usa o e-mail da conta.",
          "valores": [
            "pull",
            "webhook",
            "email"
          ]
        },
        "destino": {
          "tipo": "string",
          "desc": "Nova URL https na porta 443 (webhook). Ignorado no pull e no e-mail."
        }
      },
      "body": {
        "ativo": false
      },
      "retorno": {
        "alerta": {
          "tipo": "Alerta",
          "desc": "O alerta depois da mudança."
        }
      },
      "erros": {
        "400": "Nada para mudar ou valor inválido.",
        "401": "Sem token de convidado nem sessão da conta, token desconhecido, credencial da carteira recusada (`invalid_wallet_token`), ou `session_ended` (cookie de sessão vencida: entre de novo).",
        "402": "Reativar além da franquia, fora da janela paga, sem pagamento — `accepts[]` do x402 e o caminho do crédito.",
        "403": "`email_exige_conta`: canal e-mail sem a sessão da conta; ou `invalid_origin`/`invalid_csrf` na escrita com o cookie da conta.",
        "404": "Alerta inexistente ou de outro dono.",
        "502": "`pago_nao_registrado`: o pagamento da reativação entrou e a gravação falhou — guarde o `recibo`; o alerta segue pausado.",
        "503": "Canal e-mail desligado."
      },
      "exemplo": "curl -s -XPATCH $ORIGIN/api/alertas/$ID -H \"Authorization: Bearer $EDM\" -H 'content-type: application/json' -d '{\"ativo\":false}'",
      "returns": "{ alerta{id,nome,organizacao,destinatarios,resultados,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url,compras_total} }",
      "url": "https://editalmd.com/api/alertas/:id",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "DELETE",
      "path": "/api/alertas/:id",
      "auth": "owner",
      "summary": "Apaga o alerta e o histórico de compras casadas. Sem volta.",
      "grupo": "Acompanhar",
      "params": {
        "id": {
          "desc": "Identificador do alerta.",
          "exemplo": "9f3c…"
        }
      },
      "retorno": {
        "_texto": "204 sem corpo."
      },
      "erros": {
        "401": "Sem token de convidado nem sessão da conta, token desconhecido, credencial da carteira recusada (`invalid_wallet_token`), ou `session_ended` (cookie de sessão vencida: entre de novo).",
        "403": "`invalid_origin` / `invalid_csrf`: escrita com o cookie da conta fora da mesma origem ou sem X-CSRF-Token.",
        "404": "Alerta inexistente ou de outro dono.",
        "503": "`conta_indisponivel`: conta fora do ar agora; nada muda."
      },
      "exemplo": "curl -s -XDELETE $ORIGIN/api/alertas/$ID -H \"Authorization: Bearer $EDM\"",
      "returns": "204 sem corpo.",
      "url": "https://editalmd.com/api/alertas/:id",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "POST",
      "path": "/api/vigias",
      "auth": "owner",
      "summary": "Vigia uma compra: fotografa agora e avisa quando mudar — documento novo, suspensão, prazo adiado, valor — e nos prazos.",
      "grupo": "Acompanhar",
      "desc": "A primeira vigia ativa é grátis (`FRANQUIA_VIGIAS`); as seguintes custam `PRECO_VIGIA` até 30 dias após o encerramento. Repetir a mesma compra, canal e destino deste dono retorna a vigia ativa com 200, sem nova cobrança; criação retorna 201. As verificações são periódicas; confira a data da última verificação na vigia. Avisos `prazo_impugnacao` (no dia) e `prazo_proposta` (24 h antes) saem uma vez cada.",
      "corpo": {
        "compra_id": {
          "tipo": "int",
          "desc": "Identificador da compra no acervo, vindo da busca.",
          "obrigatorio": true
        },
        "canal": {
          "tipo": "string",
          "desc": "`pull` (ler em `/eventos`), `webhook` ou `email` (e-mail verificado da conta; exige sessão).",
          "valores": [
            "pull",
            "webhook",
            "email"
          ],
          "padrao": "pull"
        },
        "destino": {
          "tipo": "string",
          "desc": "URL https pública na porta 443, sem credencial (webhook). Ignorado no pull e no e-mail."
        }
      },
      "body": {
        "compra_id": 42,
        "canal": "pull"
      },
      "retorno": {
        "vigia": {
          "tipo": "Vigia",
          "desc": "A vigia criada ou a ativa já existente deste dono."
        },
        "snapshot": {
          "tipo": "Snapshot",
          "desc": "A fotografia inicial da compra."
        },
        "pagamento": {
          "tipo": "object",
          "desc": "`via` (franquia, credito, x402 ou existente), `preco_usd` e `pago_ate`. Repetição: `via: existente`, `preco_usd: $0.00`, `repetido: true`."
        }
      },
      "erros": {
        "400": "`compra_id`, canal ou destino inválidos.",
        "401": "Sem token de convidado nem sessão da conta, token desconhecido, credencial da carteira recusada (`invalid_wallet_token`), ou `session_ended` (cookie de sessão vencida: entre de novo).",
        "402": "Acima da franquia sem pagamento — `accepts[]` do x402 e o caminho do crédito.",
        "403": "`email_exige_conta`: canal e-mail sem a sessão da conta; ou `invalid_origin`/`invalid_csrf` na escrita com o cookie da conta.",
        "404": "Compra não encontrada no acervo.",
        "502": "`pago_nao_registrado`: o pagamento entrou e a gravação da compra falhou — guarde o `recibo`; a vigia não foi criada.",
        "503": "Canal e-mail desligado, ou origem indisponível."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/vigias -H \"Authorization: Bearer $EDM\" -H 'content-type: application/json' -d '{\"compra_id\":42}'",
      "returns": "{ vigia{id,compra_id,canal,destino,ativo,pago_ate,ultimo_check,criado_em,vigia_url,eventos_url,compra_url}, snapshot{situacao_id,situacao,encerramento_proposta,valor_estimado,atualizado_em,documentos}, pagamento }",
      "url": "https://editalmd.com/api/vigias",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "GET",
      "path": "/api/vigias",
      "auth": "owner",
      "summary": "Lista as vigias deste dono, as mais novas primeiro.",
      "grupo": "Acompanhar",
      "retorno": {
        "itens": {
          "tipo": "Vigia[]",
          "desc": "Até 50 vigias do dono."
        },
        "franquia_vigias": {
          "tipo": "int",
          "desc": "Quantas vigias ativas são grátis."
        }
      },
      "erros": {
        "401": "Sem token de convidado nem sessão da conta, token desconhecido, credencial da carteira recusada (`invalid_wallet_token`), ou `session_ended` (cookie de sessão vencida: entre de novo).",
        "403": "`invalid_origin` / `invalid_csrf`: escrita com o cookie da conta fora da mesma origem ou sem X-CSRF-Token.",
        "503": "`conta_indisponivel`: conta fora do ar agora; nada muda."
      },
      "exemplo": "curl -s $ORIGIN/api/vigias -H \"Authorization: Bearer $EDM\"",
      "returns": "{ itens[{id,compra_id,canal,destino,ativo,pago_ate,ultimo_check,criado_em,vigia_url,eventos_url,compra_url}], franquia_vigias }",
      "url": "https://editalmd.com/api/vigias",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "GET",
      "path": "/api/vigias/:id",
      "auth": "owner",
      "summary": "Uma vigia do dono com a fotografia mais recente da compra.",
      "grupo": "Acompanhar",
      "params": {
        "id": {
          "desc": "Identificador da vigia, devolvido na criação.",
          "exemplo": "2b7e…"
        }
      },
      "retorno": {
        "vigia": {
          "tipo": "Vigia",
          "desc": "A vigia."
        },
        "snapshot": {
          "tipo": "Snapshot",
          "desc": "O que o cron viu por último."
        }
      },
      "erros": {
        "401": "Sem token de convidado nem sessão da conta, token desconhecido, credencial da carteira recusada (`invalid_wallet_token`), ou `session_ended` (cookie de sessão vencida: entre de novo).",
        "403": "`invalid_origin` / `invalid_csrf`: escrita com o cookie da conta fora da mesma origem ou sem X-CSRF-Token.",
        "404": "Vigia inexistente ou de outro dono.",
        "503": "`conta_indisponivel`: conta fora do ar agora; nada muda."
      },
      "exemplo": "curl -s $ORIGIN/api/vigias/$ID -H \"Authorization: Bearer $EDM\"",
      "returns": "{ vigia{id,compra_id,canal,destino,ativo,pago_ate,ultimo_check,criado_em,vigia_url,eventos_url,compra_url}, snapshot{situacao_id,situacao,encerramento_proposta,valor_estimado,atualizado_em,documentos} }",
      "url": "https://editalmd.com/api/vigias/:id",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "GET",
      "path": "/api/vigias/:id/eventos",
      "auth": "owner",
      "summary": "O que mudou na compra vigiada, evento a evento — é a série temporal e o canal pull.",
      "grupo": "Acompanhar",
      "params": {
        "id": {
          "desc": "Identificador da vigia.",
          "exemplo": "2b7e…"
        }
      },
      "query": {
        "limite": {
          "tipo": "int",
          "desc": "1 a 100 (padrão 50), mais recentes primeiro."
        }
      },
      "retorno": {
        "vigia": {
          "tipo": "Vigia",
          "desc": "A vigia."
        },
        "snapshot": {
          "tipo": "Snapshot",
          "desc": "A fotografia atual."
        },
        "itens": {
          "tipo": "Evento[]",
          "desc": "Eventos registrados."
        },
        "limite": {
          "tipo": "int",
          "desc": "Teto aplicado."
        }
      },
      "erros": {
        "401": "Sem token de convidado nem sessão da conta, token desconhecido, credencial da carteira recusada (`invalid_wallet_token`), ou `session_ended` (cookie de sessão vencida: entre de novo).",
        "403": "`invalid_origin` / `invalid_csrf`: escrita com o cookie da conta fora da mesma origem ou sem X-CSRF-Token.",
        "404": "Vigia inexistente ou de outro dono.",
        "503": "`conta_indisponivel`: conta fora do ar agora; nada muda."
      },
      "exemplo": "curl -s \"$ORIGIN/api/vigias/$ID/eventos?limite=20\" -H \"Authorization: Bearer $EDM\"",
      "returns": "{ vigia{id,compra_id,canal,destino,ativo,pago_ate,ultimo_check,criado_em,vigia_url,eventos_url,compra_url}, snapshot{situacao_id,situacao,encerramento_proposta,valor_estimado,atualizado_em,documentos}, itens[{id,tipo,antes,depois,visto_em,entregue_em}], limite }",
      "url": "https://editalmd.com/api/vigias/:id/eventos",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "DELETE",
      "path": "/api/vigias/:id",
      "auth": "owner",
      "summary": "Apaga a vigia e seus eventos. Sem volta.",
      "grupo": "Acompanhar",
      "params": {
        "id": {
          "desc": "Identificador da vigia.",
          "exemplo": "2b7e…"
        }
      },
      "retorno": {
        "_texto": "204 sem corpo."
      },
      "erros": {
        "401": "Sem token de convidado nem sessão da conta, token desconhecido, credencial da carteira recusada (`invalid_wallet_token`), ou `session_ended` (cookie de sessão vencida: entre de novo).",
        "403": "`invalid_origin` / `invalid_csrf`: escrita com o cookie da conta fora da mesma origem ou sem X-CSRF-Token.",
        "404": "Vigia inexistente ou de outro dono.",
        "503": "`conta_indisponivel`: conta fora do ar agora; nada muda."
      },
      "exemplo": "curl -s -XDELETE $ORIGIN/api/vigias/$ID -H \"Authorization: Bearer $EDM\"",
      "returns": "204 sem corpo.",
      "url": "https://editalmd.com/api/vigias/:id",
      "auth_detail": "Convidado edm_… assinado pelo SDK (POST /api/guest, sem cadastro), enviado em X-Guest-Token ou Authorization: Bearer; nos bancos fica só seu SHA-256. Também aceita a sessão da conta, dona direta das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Vincular a conta transfere os dados temporários pelo claim do SDK. Agente sem conta: a credencial da carteira (Authorization: Bearer mmw_…, de POST /api/auth/wallet/agent/start) é dona como um convidado, x402:<endereço>; o que ela fez passa para a conta a que a carteira for vinculada. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "method": "GET",
      "path": "/api/credito/x402/saude",
      "auth": "none",
      "exemplo": "curl -s $ORIGIN/api/credito/x402/saude",
      "grupo": "Crédito",
      "summary": "Saúde do verificador x402: pendências, falta de hash e falha ou parada da conciliação.",
      "retorno": {
        "verificado_em": {
          "tipo": "string",
          "desc": "Hora da leitura, em UTC."
        },
        "ativo": {
          "tipo": "boolean",
          "desc": "Verificador configurado no processo."
        },
        "tarefas": {
          "tipo": "object[]",
          "desc": "Falhas com id e motivo, sem dados do pagador. Contagem limitada indica +."
        }
      },
      "erros": {
        "503": "Verificador indisponível neste processo."
      },
      "returns": "{ verificado_em, ativo, tarefas }",
      "url": "https://editalmd.com/api/credito/x402/saude",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/credito/barrados/saude",
      "auth": "none",
      "exemplo": "curl -s $ORIGIN/api/credito/barrados/saude",
      "grupo": "Crédito",
      "summary": "Quem pagou e foi barrado neste site nas últimas 24 horas: a casa pediu pagamento a quem tinha saldo ou plano, ou cobrou e não entregou.",
      "retorno": {
        "verificado_em": {
          "tipo": "string",
          "desc": "Hora da leitura, em UTC."
        },
        "ativo": {
          "tipo": "boolean",
          "desc": "A leitura funcionou."
        },
        "total": {
          "tipo": "int",
          "desc": "Quantas ocorrências diferentes houve."
        },
        "tarefas": {
          "tipo": "object[]",
          "desc": "Até 8 ocorrências, com classe, rota, vezes e última hora, sem dados de quem pagou."
        }
      },
      "returns": "{ verificado_em, ativo, total, tarefas }",
      "url": "https://editalmd.com/api/credito/barrados/saude",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/credito/conta",
      "auth": "credito",
      "exemplo": "curl -s $ORIGIN/api/credito/conta -H 'Cookie: <sessão>'",
      "grupo": "Crédito",
      "summary": "O saldo da conta da sessão: a soma das compras dela neste ambiente, em todo produto, sem precisar do código. Com movimentos=1, o extrato da conta.",
      "query": {
        "movimentos": {
          "tipo": "string",
          "desc": "`1`: consulta só o extrato paginado da conta, sem saldo."
        },
        "de": {
          "tipo": "string",
          "desc": "Início inclusivo em UTC ISO 8601 com milissegundos. Padrão: 1970-01-01T00:00:00.000Z."
        },
        "ate": {
          "tipo": "string",
          "desc": "Fim exclusivo em UTC ISO 8601 com milissegundos. Padrão: agora. Conserve o valor entre páginas."
        },
        "antes": {
          "tipo": "string",
          "desc": "Cursor `proximo` da página anterior. Só com movimentos=1."
        },
        "limite": {
          "tipo": "int",
          "desc": "1 a 50 movimentos por página; padrão 20. Só com movimentos=1."
        }
      },
      "retorno": {
        "saldo_micros": {
          "tipo": "int",
          "desc": "O saldo em milionésimos de dólar."
        },
        "saldo_usd": {
          "tipo": "string",
          "desc": "O saldo em dólar, formatado."
        },
        "referencia_usd": {
          "tipo": "string",
          "desc": "O saldo logo depois da última recarga, somado nas carteiras com saldo: a base do que resta."
        },
        "cotacao_brl_por_usd": {
          "tipo": "number",
          "desc": "A cotação do real que a tela usa para mostrar o saldo."
        },
        "movimentos": {
          "tipo": "object[]",
          "desc": "Só com movimentos=1: id, em, valor_usd, saldo_usd, motivo, produto e recurso, do mais novo."
        },
        "proximo": {
          "tipo": "string",
          "desc": "Só com movimentos=1: cursor da próxima página ou null."
        }
      },
      "erros": {
        "400": "Período, limite ou cursor inválido.",
        "401": "Sem sessão."
      },
      "returns": "{ saldo_micros, saldo_usd, referencia_usd, cotacao_brl_por_usd, movimentos, proximo }",
      "url": "https://editalmd.com/api/credito/conta",
      "auth_detail": "Token de crédito em `Authorization: Bearer cred_…` (ou `X-Credito`). Para saldo recuperado de x402, use a credencial de carteira `mmw_…` em Bearer ou `X-Wallet-Token`, emitida por `/api/auth/wallet/agent/start` e `/api/auth/wallet/agent/token`."
    },
    {
      "method": "POST",
      "path": "/api/credito/conta",
      "auth": "credito",
      "exemplo": "curl -s -XPOST $ORIGIN/api/credito/conta -H 'Authorization: Bearer cred_…' -H 'Cookie: <sessão>'",
      "grupo": "Crédito",
      "summary": "Liga à conta da sessão o crédito comprado sem conta, inclusive em USDC, com o plano de consultas pago por ele. Depois disso, o saldo vale nos produtos do crédito da casa com `X-Credito: conta`, somado ao das outras compras da conta.",
      "retorno": {
        "ok": {
          "tipo": "boolean",
          "desc": "A ligação foi conferida."
        },
        "ligadas": {
          "tipo": "int",
          "desc": "Compras ligadas agora. Zero quando a compra já tem conta."
        },
        "da_conta": {
          "tipo": "boolean",
          "desc": "O saldo deste código já vem no saldo da conta."
        }
      },
      "erros": {
        "401": "Sem sessão ou sem o código de crédito."
      },
      "returns": "{ ok, ligadas, da_conta }",
      "url": "https://editalmd.com/api/credito/conta",
      "auth_detail": "Token de crédito em `Authorization: Bearer cred_…` (ou `X-Credito`). Para saldo recuperado de x402, use a credencial de carteira `mmw_…` em Bearer ou `X-Wallet-Token`, emitida por `/api/auth/wallet/agent/start` e `/api/auth/wallet/agent/token`."
    },
    {
      "method": "POST",
      "path": "/api/credito",
      "auth": "none",
      "summary": "Recarrega crédito pré-pago: paga uma vez com x402 e recebe o token que desconta em qualquer API da casa.",
      "grupo": "Crédito",
      "preco_usd_faixa": [
        0.1,
        25
      ],
      "query": {
        "usd": {
          "tipo": "number",
          "desc": "Pacote: 0.1, 1, 5, 10 ou 25 dólares.",
          "obrigatorio": true,
          "enum": [
            0.1,
            1,
            5,
            10,
            25
          ]
        }
      },
      "retorno": {
        "token": {
          "tipo": "string",
          "desc": "Token portador do saldo (`cred_…`). Mostrado UMA vez — não há como recuperá-lo."
        },
        "saldo_usd": {
          "tipo": "string",
          "desc": "Saldo creditado."
        },
        "guarde": {
          "tipo": "string",
          "desc": "Aviso de que o token é o portador do crédito."
        },
        "usar": {
          "tipo": "string",
          "desc": "Como apresentar o token nas rotas pagas."
        },
        "usar_com_outra_credencial": {
          "tipo": "string",
          "desc": "O header `X-Credito`, para quando o `Authorization` já leva outra credencial."
        },
        "saldo_em": {
          "tipo": "string",
          "desc": "Onde consultar saldo e extrato."
        },
        "onde_gastar": {
          "tipo": "object",
          "desc": "`precos`: as ações pagas e os preços deste produto (`/api/pricing`); `produtos`: o APIs.json com os outros produtos da casa."
        }
      },
      "erros": {
        "400": "Pacote fora da lista (0.1, 1, 5, 10 ou 25).",
        "402": "Sem pagamento — o corpo traz `accepts[]` do x402."
      },
      "exemplo": "curl -s -XPOST '$ORIGIN/api/credito?usd=10'",
      "returns": "{ token, saldo_usd, guarde, usar, usar_com_outra_credencial, saldo_em, onde_gastar }",
      "url": "https://editalmd.com/api/credito",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/credito",
      "auth": "credito",
      "summary": "Saldo e extrato com cred_…; com mmw_…, saldo da carteira e até 20 pagamentos em recuperação.",
      "grupo": "Crédito",
      "query": {
        "movimentos": {
          "tipo": "string",
          "desc": "`1`: consulta só o histórico paginado, sem saldo."
        },
        "de": {
          "tipo": "string",
          "desc": "Início inclusivo em UTC ISO 8601 com milissegundos. Padrão: 1970-01-01T00:00:00.000Z."
        },
        "ate": {
          "tipo": "string",
          "desc": "Fim exclusivo em UTC ISO 8601 com milissegundos. Padrão: agora. Conserve o valor entre páginas."
        },
        "antes": {
          "tipo": "string",
          "desc": "Cursor `proximo` da página anterior. Só com movimentos=1."
        },
        "limite": {
          "tipo": "int",
          "desc": "1 a 50 movimentos por página; padrão 20. Só com movimentos=1."
        }
      },
      "retorno": {
        "saldo_micros": {
          "tipo": "int",
          "desc": "Saldo em micro-dólares (1e-6 USD)."
        },
        "saldo_usd": {
          "tipo": "string",
          "desc": "Saldo formatado."
        },
        "criado_em": {
          "tipo": "string",
          "desc": "Quando o crédito foi aberto."
        },
        "movimentos": {
          "tipo": "object[]",
          "desc": "Entradas e saídas recentes, com produto e recurso."
        },
        "wallet": {
          "tipo": "string",
          "desc": "Só com mmw_…: endereço autenticado da carteira."
        },
        "payments": {
          "tipo": "object[]",
          "desc": "Só com mmw_…: até 20 pagamentos, com id, produto, rede, tx_hash, micros, estado e criado_ms. creditado indica saldo recuperado."
        },
        "proximo": {
          "tipo": "string|null",
          "desc": "Só com movimentos=1: cursor da próxima página ou null; movimentos inclui id, em, valor_usd, saldo_usd, motivo, produto e recurso."
        },
        "onde_gastar": {
          "tipo": "object",
          "desc": "`precos`: as ações pagas e os preços deste produto; `produtos`: o APIs.json com os outros produtos da casa."
        }
      },
      "erros": {
        "400": "Período, limite ou cursor inválido.",
        "401": "Sem token ou token desconhecido."
      },
      "exemplo": "curl -s $ORIGIN/api/credito -H 'Authorization: Bearer cred_…'",
      "returns": "{ saldo_micros, saldo_usd, criado_em, movimentos, wallet, payments, proximo, onde_gastar }",
      "url": "https://editalmd.com/api/credito",
      "auth_detail": "Token de crédito em `Authorization: Bearer cred_…` (ou `X-Credito`). Para saldo recuperado de x402, use a credencial de carteira `mmw_…` em Bearer ou `X-Wallet-Token`, emitida por `/api/auth/wallet/agent/start` e `/api/auth/wallet/agent/token`."
    },
    {
      "method": "GET",
      "path": "/api/credito/pix",
      "auth": "none",
      "summary": "Crédito por Pix: a chave, o câmbio fixo, os pacotes em reais e o que o comprovante aceita.",
      "grupo": "Crédito",
      "retorno": {
        "chave": {
          "tipo": "string",
          "desc": "A chave Pix que recebe o pagamento."
        },
        "brl_por_usd": {
          "tipo": "number",
          "desc": "Câmbio fixo usado nos pacotes."
        },
        "pacotes": {
          "tipo": "object[]",
          "desc": "Os pacotes (3, 5, 10 ou 25 dólares), cada um com `brl_centavos` e `copia_e_cola` (o Pix copia e cola do valor, o mesmo texto do QR: o app do banco já vem com o valor)."
        },
        "comprovante": {
          "tipo": "object",
          "desc": "Tipos aceitos (foto ou PDF) e o tamanho máximo, em bytes."
        },
        "liberacao": {
          "tipo": "string",
          "desc": "`manual`: o dono confere o Pix e libera."
        }
      },
      "exemplo": "curl -s $ORIGIN/api/credito/pix",
      "returns": "{ chave, brl_por_usd, pacotes, comprovante, liberacao }",
      "url": "https://editalmd.com/api/credito/pix",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/credito/pix",
      "auth": "none",
      "summary": "Pede crédito pago por Pix: multipart com `usd`, `comprovante` (foto ou PDF até 2 MB) e `email`; o resto é opcional.",
      "desc": "O código de crédito sai na resposta e passa a valer quando o dono confere o Pix e libera (manual, em geral no mesmo dia). O `email` é obrigatório: é por ele que o dono fala com a pessoa. Opcionais: `nome`, `pagina` (a página de onde pediu, até 2.000 caracteres) e o que a pessoa comprava quando recebeu o 402 — `recurso` (até 2.000), `descricao` (até 300) e `preco_usd` (decimal, ex. `0.50`); e `navegador_id` (UUID que liga os pedidos do mesmo navegador). Tudo o que chega fica registrado no pedido — o comprovante inclusive —, com a conta logada (conferida pelo cookie da sessão), a rede e o navegador de quem pediu.",
      "grupo": "Crédito",
      "retorno": {
        "id": {
          "tipo": "string",
          "desc": "Id do pedido, para acompanhar."
        },
        "estado": {
          "tipo": "string",
          "desc": "`pendente` até a decisão."
        },
        "credito": {
          "tipo": "string",
          "desc": "O token `cred_…`, mostrado UMA vez; vale depois da liberação."
        },
        "estado_em": {
          "tipo": "string",
          "desc": "Onde acompanhar o pedido."
        }
      },
      "erros": {
        "400": "Pacote fora da lista (3, 5, 10 ou 25), sem comprovante ou sem e-mail válido.",
        "413": "Comprovante acima de 2 MB.",
        "415": "Comprovante que não é foto (JPEG, PNG, WebP) nem PDF.",
        "429": "A rede já mandou os pedidos do dia.",
        "502": "O e-mail ao dono não saiu: o pedido fica registrado como `falhou`; mande de novo.",
        "503": "Fila de conferência cheia, ou Pix indisponível neste app."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/credito/pix -F usd=5 -F email=voce@empresa.com.br -F comprovante=@pix.pdf",
      "returns": "{ id, estado, credito, estado_em }",
      "url": "https://editalmd.com/api/credito/pix",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/credito/pix/:id",
      "auth": "none",
      "summary": "Estado de um pedido de crédito por Pix: `pendente`, `liberado`, `recusado` ou `falhou`.",
      "grupo": "Crédito",
      "params": {
        "id": {
          "desc": "Id do pedido (32 hex).",
          "exemplo": "0123456789abcdef0123456789abcdef"
        }
      },
      "retorno": {
        "estado": {
          "tipo": "string",
          "desc": "`pendente`, `liberado`, `recusado` ou `falhou` (o e-mail ao dono não saiu; mande de novo)."
        },
        "usd": {
          "tipo": "int",
          "desc": "O pacote pedido."
        },
        "decidido_em": {
          "tipo": "string",
          "desc": "Quando o dono decidiu, ou `null`."
        }
      },
      "erros": {
        "404": "Pedido desconhecido."
      },
      "exemplo": "curl -s $ORIGIN/api/credito/pix/0123456789abcdef0123456789abcdef",
      "returns": "{ estado, usd, decidido_em }",
      "url": "https://editalmd.com/api/credito/pix/:id",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/credito/asaas/:id/cancelar",
      "auth": "none",
      "grupo": "Crédito",
      "summary": "Cancela uma cobrança pendente ao fechar o pagamento.",
      "desc": "Exige o bilhete `cancelamento` devolvido na criação. Uma cobrança antiga de crédito aceita seu token em `credito`. Só atua no produto e ambiente de origem. Não estorna pagamentos nem remove o histórico. 202 indica cancelamento em andamento; a vigia retoma falhas externas.",
      "params": {
        "id": {
          "desc": "Id da cobrança (32 hex).",
          "exemplo": "0123456789abcdef0123456789abcdef"
        }
      },
      "retorno": {
        "id": {
          "tipo": "string",
          "desc": "Id da cobrança."
        },
        "estado": {
          "tipo": "string",
          "desc": "`cancelando`, `vencido` ou o estado final já confirmado."
        }
      },
      "erros": {
        "404": "Cobrança ou bilhete inválido, produto ou ambiente diferente."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/credito/asaas/0123456789abcdef0123456789abcdef/cancelar -H 'content-type: application/json' -d '{\"cancelamento\":\"<bilhete>\"}'",
      "returns": "{ id, estado }",
      "url": "https://editalmd.com/api/credito/asaas/:id/cancelar",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/credito/asaas",
      "auth": "none",
      "summary": "Pix automático: se está disponível neste app, os pacotes em reais e o saldo que o produto vende.",
      "grupo": "Crédito",
      "retorno": {
        "disponivel": {
          "tipo": "boolean",
          "desc": "`false` quando o app não tem o Asaas configurado (use o Pix com comprovante)."
        },
        "pacotes": {
          "tipo": "object[]",
          "desc": "Os pacotes de crédito (3, 5, 10 ou 25 dólares), com `brl_centavos`."
        },
        "exatos": {
          "tipo": "object[]",
          "desc": "Preços declarados pelo app, com `usd` e `brl_centavos`. Só aparecem a partir de R$ 5,00 e até R$ 10.000."
        },
        "saldo": {
          "tipo": "object",
          "desc": "Quando o produto vende saldo em reais: a faixa e se a conta logada pode comprar."
        },
        "precisa_documento": {
          "tipo": "boolean",
          "desc": "Se o CPF ou CNPJ de quem paga ainda é pedido."
        }
      },
      "exemplo": "curl -s $ORIGIN/api/credito/asaas",
      "returns": "{ disponivel, pacotes, exatos, saldo, precisa_documento }",
      "url": "https://editalmd.com/api/credito/asaas",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/credito/asaas",
      "auth": "none",
      "summary": "Gera um Pix dinâmico: JSON com `oferta` (`pacote` com `usd`, ou `saldo` com `centavos`) e o pagador.",
      "desc": "O pagamento libera sozinho o que se comprou: o pacote vira o token `cred_…` que já vem na resposta; o saldo cai na organização da conta logada. Na primeira compra vão `documento` (CPF ou CNPJ, que segue para o gateway e não fica guardado aqui) e `nome`; `email`, `pagina` e `navegador_id` são opcionais e ficam registrados. Com `forma: \"cartao_boleto\"`, a cobrança é livre: a resposta traz `pagamento_em`, a página do gateway onde se paga com cartão, boleto ou Pix (vence em três dias). Com `forma: \"cartao\"` e o `cartao` (`titular`, `numero`, `mes`, `ano`, `cvv`, `documento`, `email`, `cep`, `numero_endereco`, `telefone`), a cobrança é paga no cartão no mesmo pedido: 200 com `estado: \"pago\"`, 202 com `conferir` enquanto o emissor analisa, 422 quando o cartão é recusado; o cartão não fica guardado. O `usd` deve ser um valor de `pacotes` ou `exatos` do GET. O servidor define os centavos e recusa valores não declarados.",
      "grupo": "Crédito",
      "retorno": {
        "id": {
          "tipo": "string",
          "desc": "Id da cobrança, para acompanhar."
        },
        "credito": {
          "tipo": "string",
          "desc": "No pacote: o token `cred_…`, mostrado UMA vez; vale quando o pagamento cair."
        },
        "forma": {
          "tipo": "string",
          "desc": "`pix` (o padrão), `cartao` ou `cartao_boleto`."
        },
        "pix": {
          "tipo": "object",
          "desc": "`copia_e_cola`, `imagem` (QR em PNG, data URI) e `expira_em`; só na forma `pix`."
        },
        "pagamento_em": {
          "tipo": "string",
          "desc": "Na forma `cartao_boleto`: a página de pagamento do gateway."
        },
        "estado": {
          "tipo": "string",
          "desc": "Na forma `cartao`: `pago`, ou `pendente` com `conferir`."
        },
        "estado_em": {
          "tipo": "string",
          "desc": "Onde acompanhar o pagamento."
        },
        "cancelamento": {
          "tipo": "string",
          "desc": "Bilhete para cancelar a cobrança pendente de Pix ou boleto."
        }
      },
      "erros": {
        "400": "Crédito fora de `pacotes` e `exatos`, valor fora da faixa, CPF/CNPJ, nome ou e-mail inválido, dado do cartão inválido (`cartao_dados`, com o `campo`), ou o gateway recusou o pagador (`pagador_recusado`, com a razão em `detalhe`).",
        "422": "Cartão recusado (`cartao_recusado`, com o `campo` quando o gateway diz qual); troque em `POST /api/credito/asaas/:id/cartao`.",
        "429": "Limite de 3 tentativas por minuto ou 10 por dia, por conta ou rede, ou limite do cartão.",
        "502": "O gateway não gerou o Pix; tente de novo.",
        "503": "Pix automático indisponível neste app, o gateway ocupado (`asaas_ocupado`, espere `retry_after_s`), ou cobranças demais de quem não entrou esperando pagamento."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/credito/asaas -H 'content-type: application/json' -d '{\"oferta\":\"pacote\",\"usd\":5,\"documento\":\"000.000.000-00\",\"nome\":\"Ana\"}'",
      "returns": "{ id, credito, forma, pix, pagamento_em, estado, estado_em, cancelamento }",
      "url": "https://editalmd.com/api/credito/asaas",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/credito/asaas/:id",
      "auth": "none",
      "summary": "Estado de uma cobrança Pix automática: `pendente`, `pago`, `vencido`, `estornado` ou `falhou`.",
      "grupo": "Crédito",
      "params": {
        "id": {
          "desc": "Id da cobrança (32 hex).",
          "exemplo": "0123456789abcdef0123456789abcdef"
        }
      },
      "retorno": {
        "estado": {
          "tipo": "string",
          "desc": "`pago` libera o token do pacote ou o saldo; o Pix pago depois do vencimento vale."
        },
        "pago_em": {
          "tipo": "string",
          "desc": "Quando o pagamento foi confirmado, ou `null`."
        }
      },
      "erros": {
        "404": "Cobrança desconhecida."
      },
      "exemplo": "curl -s $ORIGIN/api/credito/asaas/0123456789abcdef0123456789abcdef",
      "returns": "{ estado, pago_em }",
      "url": "https://editalmd.com/api/credito/asaas/:id",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/credito/asaas/:id/cartao",
      "auth": "none",
      "summary": "Paga com outro cartão a cobrança de cartão cujo cartão foi recusado: a mesma cobrança, sem cobrar duas vezes.",
      "desc": "JSON com o `cartao` (os mesmos campos do `POST /api/credito/asaas`) e, sem conta, o `navegador_id` que criou a cobrança. Só a cobrança de cartão que espera pagamento, de quem a criou, e até cinco tentativas por cobrança.",
      "grupo": "Crédito",
      "params": {
        "id": {
          "desc": "Id da cobrança (32 hex).",
          "exemplo": "0123456789abcdef0123456789abcdef"
        }
      },
      "retorno": {
        "estado": {
          "tipo": "string",
          "desc": "`pago`, ou `pendente` com `conferir` enquanto o emissor analisa."
        },
        "estado_em": {
          "tipo": "string",
          "desc": "Onde acompanhar o pagamento."
        }
      },
      "erros": {
        "400": "Dado do cartão inválido (`cartao_dados`, com o `campo`).",
        "404": "Cobrança desconhecida, de outra pessoa ou que não é de cartão.",
        "409": "A cobrança já venceu ou foi encerrada; comece o pagamento de novo.",
        "422": "Cartão recusado (`cartao_recusado`).",
        "429": "Passou das tentativas de cartão desta cobrança ou do dia."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/credito/asaas/0123456789abcdef0123456789abcdef/cartao -H 'content-type: application/json' -d '{\"cartao\":{…}}'",
      "returns": "{ estado, estado_em }",
      "url": "https://editalmd.com/api/credito/asaas/:id/cartao",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/credito/asaas/saude",
      "auth": "none",
      "summary": "A saúde do Pix e das assinaturas ativas deste app: falhas com motivo, para o painel.",
      "grupo": "Crédito",
      "retorno": {
        "ativo": {
          "tipo": "boolean",
          "desc": "`false` quando o Asaas e as assinaturas estão desligados."
        },
        "tarefas": {
          "tipo": "object[]",
          "desc": "Cada problema: `id`, `falhando` e `motivo`. Inclui Pix e, quando ativas, recuperação, fila e orçamento das assinaturas. Não consulta o provedor."
        }
      },
      "exemplo": "curl -s $ORIGIN/api/credito/asaas/saude",
      "returns": "{ ativo, tarefas }",
      "url": "https://editalmd.com/api/credito/asaas/saude",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/visit",
      "auth": "none",
      "summary": "O aviso da tela que soma uma visita ao dia. Agentes não precisam chamar.",
      "grupo": "Operação",
      "desc": "A tela manda o aviso no primeiro gesto de quem usa (toque, tecla ou clique), uma vez por página. Teste não conta: `X-MM-Smoke`, User-Agent `mm-smoke` ou `smoke: true` no corpo voltam com `counted: false`. Só o aviso da própria página conta: a chamada de fora de uma página do mesmo site (User-Agent de robô, ou sem `Sec-Fetch-Site: same-origin`) volta com `counted: false` e `reason: \"robo\"`.",
      "corpo": {
        "p": {
          "tipo": "string",
          "desc": "O caminho da página visitada."
        },
        "smoke": {
          "tipo": "bool",
          "desc": "`true` marca o pedido como teste, e ele não entra na conta."
        }
      },
      "body": {
        "p": "/"
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Sempre `true`."
        },
        "counted": {
          "tipo": "bool",
          "desc": "Se a visita entrou na conta do dia."
        },
        "reason": {
          "tipo": "string",
          "desc": "Por que não contou, quando `counted` é `false`.",
          "opcional": true
        }
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/visit -H 'content-type: application/json' -d '{\"p\":\"/\",\"smoke\":true}'",
      "returns": "{ ok, counted, reason? }",
      "url": "https://editalmd.com/api/visit",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/contact",
      "auth": "none",
      "summary": "Fale com quem faz o produto — de graça, para pessoa e agente.",
      "grupo": "Contato",
      "desc": "Uma rota para dúvida e para proposta de patrocínio, parceria ou anúncio (`tipo`, com os espaços de `GET /api/partners`). Sem captcha, sem conta, sem pagamento. Uma mensagem a cada 10 segundos por rede: a que chega antes espera a vez e sai — sem erro. A mensagem chega à equipe por e-mail, com o `email` como endereço de resposta. Para voz, envie multipart/form-data: `dados` contém este JSON (até 32 KiB) e `audio` contém um arquivo de áudio WebM, Ogg ou M4A (até 2 MB). O áudio pode substituir message. O navegador grava até dois minutos. O áudio vai como anexo ao e-mail do dono.",
      "corpo": {
        "name": {
          "tipo": "string",
          "desc": "Como chamar quem escreve (alias `nome`).",
          "obrigatorio": true
        },
        "email": {
          "tipo": "string",
          "desc": "Para onde responder.",
          "obrigatorio": true
        },
        "message": {
          "tipo": "string",
          "desc": "O que você quer dizer (alias `mensagem`).",
          "obrigatorio": true
        },
        "whatsapp": {
          "tipo": "string",
          "desc": "Número opcional para resposta, com código do país. Ex.: +5561999999999."
        },
        "prefer_whatsapp": {
          "tipo": "bool",
          "desc": "Pede resposta por WhatsApp. Exige whatsapp."
        },
        "tipo": {
          "tipo": "string",
          "desc": "Proposta: `patrocinio`, `parceria`, `anuncio` ou `consultoria`. Liga os campos abaixo."
        },
        "empresa": {
          "tipo": "string",
          "desc": "Quem propõe, quando é empresa."
        },
        "site": {
          "tipo": "string",
          "desc": "Site de quem propõe."
        },
        "orcamento": {
          "tipo": "string",
          "desc": "Anúncio: `ate_100`, `100_500`, `500_2000`, `2000_mais` ou `a_combinar`. Consultoria, em dólar: `ate_2000`, `2000_5000`, `5000_10000`, `10000_mais` ou `nao_sei`."
        },
        "espaco": {
          "tipo": "string[]",
          "desc": "Ids de placement de `GET /api/partners`, até 6."
        },
        "duracao": {
          "tipo": "string",
          "desc": "Dias de exposição: `30`, `90` ou `365`."
        },
        "pagamento": {
          "tipo": "string",
          "desc": "`usdc`, `deposito` ou `a_combinar`."
        },
        "projeto": {
          "tipo": "string",
          "desc": "Consultoria: o tipo de projeto (`llm_privado`, `voz`, `dados_sensiveis`, `gpu`, `integracao` ou `outro`)."
        },
        "prazo": {
          "tipo": "string",
          "desc": "Consultoria: quando começar (`agora`, `1_mes`, `1_3_meses` ou `explorando`)."
        },
        "formato": {
          "tipo": "string",
          "desc": "Consultoria: `projeto` (por escopo), `mensal` ou `assessoria`."
        },
        "pais": {
          "tipo": "string",
          "desc": "Consultoria: o país de quem pede."
        },
        "fuso": {
          "tipo": "string",
          "desc": "Consultoria: o fuso IANA, como `America/New_York`."
        },
        "horarios": {
          "tipo": "string[]",
          "desc": "Consultoria: até 3 horários para a conversa, `AAAA-MM-DDTHH:MM` na hora do fuso."
        }
      },
      "body": {
        "name": "Agente",
        "email": "agent@example.com",
        "message": "olá, sou um agente"
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Sempre `true` quando a mensagem foi aceita."
        }
      },
      "erros": {
        "400": "Validação: o `code` diz o campo.",
        "503": "O contato não está configurado neste servidor."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/contact -H 'content-type: application/json' -d '{\"name\":\"Agente\",\"email\":\"agent@example.com\",\"message\":\"olá, sou um agente\"}'",
      "returns": "{ ok }",
      "url": "https://editalmd.com/api/contact",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/erro-cliente",
      "auth": "none",
      "summary": "Relato de erro do navegador, enviado pela própria interface. Agente não precisa chamar.",
      "grupo": "Operação",
      "desc": "A interface relata sozinha erro de JS, promessa rejeitada, script/CSS que não carregou e bloqueio de CSP — uma vez por sessão — e o app relata falha tratada por `window.mmErro.relata`. O servidor valida o envelope, redige credencial, e-mail e telefone, junta repetições da mesma falha por minuto e registra um evento operacional; nada é gravado em banco. Não guarda IP, cookie, query nem o User-Agent inteiro. Responde 204 sempre, inclusive para relato inválido.",
      "corpo": {
        "code": {
          "tipo": "string",
          "desc": "Código da falha, `UI-` + letras/dígitos (`UI-JS-001` erro global, `UI-PROMESSA-001`, `UI-RECURSO-001`, `UI-CSP-001`, `UI-APP-001` relato do app).",
          "obrigatorio": true
        },
        "phase": {
          "tipo": "string",
          "desc": "Fase em que quebrou, minúsculas: `global`, `promessa`, `script`, `carregar_lista`…",
          "obrigatorio": true
        },
        "path": {
          "tipo": "string",
          "desc": "Caminho da página aberta, sem query; número, hash e token no caminho são guardados como `:id`."
        },
        "message": {
          "tipo": "string",
          "desc": "Mensagem do erro, até 2000 caracteres."
        },
        "stack": {
          "tipo": "string",
          "desc": "Stack trace, até 12000 caracteres."
        },
        "source": {
          "tipo": "string",
          "desc": "Script de origem; só o caminho é guardado."
        },
        "line": {
          "tipo": "int",
          "desc": "Linha no script de origem."
        },
        "column": {
          "tipo": "int",
          "desc": "Coluna no script de origem."
        },
        "visivel": {
          "tipo": "bool",
          "desc": "Se a aba estava visível quando quebrou."
        },
        "build": {
          "tipo": "string",
          "desc": "Build da página que relatou (a `<meta name=\"build\">`), até 64 letras, dígitos, `.`, `_` ou `-`; é ele que data a falha."
        }
      },
      "body": {
        "code": "UI-APP-001",
        "phase": "carregar_lista",
        "path": "/",
        "message": "lista 500"
      },
      "retorno": {
        "_texto": "204 sem corpo, sempre — relato inválido, repetido ou acima do teto também recebe 204."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/erro-cliente -H 'content-type: application/json' -d '{\"code\":\"UI-APP-001\",\"phase\":\"carregar_lista\",\"path\":\"/\",\"message\":\"lista 500\"}'",
      "returns": "204 sem corpo, sempre — relato inválido, repetido ou acima do teto também recebe 204.",
      "url": "https://editalmd.com/api/erro-cliente",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/pagamento/aberto",
      "auth": "none",
      "statusOk": 202,
      "summary": "A interface relata que exibiu uma cobrança. Agentes não devem chamar.",
      "grupo": "Operação",
      "desc": "Relato sem corpo, da mesma origem, enviado automaticamente quando uma cobrança fica visível. Não inicia pagamento, não concede acesso e não recebe identidade ou credencial. Não grava banco por relato. Conta eventos, não pessoas únicas. O painel privado do operador separa pedidos de pagamento da API e aberturas da interface por dia UTC; os dois números podem se sobrepor.",
      "headers": {
        "Origin": {
          "tipo": "string",
          "desc": "A origem da página, idêntica à desta rota.",
          "obrigatorio": true
        },
        "Sec-Fetch-Site": {
          "tipo": "string",
          "desc": "`same-origin`, definido pelo navegador.",
          "obrigatorio": true
        },
        "X-MM-Payment-View": {
          "tipo": "string",
          "desc": "`1`, definido pelo componente comum.",
          "obrigatorio": true
        }
      },
      "retorno": {
        "_texto": "202 sem corpo se aceito; 204 se ignorado. Sempre no-store."
      },
      "returns": "202 sem corpo se aceito; 204 se ignorado. Sempre no-store.",
      "url": "https://editalmd.com/api/pagamento/aberto",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/funil",
      "auth": "none",
      "statusOk": 202,
      "summary": "A interface relata os passos da visita (funil de conversão). Agentes não devem chamar.",
      "grupo": "Operação",
      "desc": "Lote da mesma origem, enviado pela própria página: páginas vistas, engajamento, oferta à vista, clique em comprar, janela de pagamento, pagamento enviado ou aceito. Guarda o id aleatório do navegador, o caminho sem query, o host de quem mandou a pessoa e as utm; nunca IP, e-mail ou conta. Não grava banco: uma linha por lote no diário do dia, com teto. Robô declarado e smoke ficam de fora.",
      "headers": {
        "Origin": {
          "tipo": "string",
          "desc": "A origem da página, idêntica à desta rota.",
          "obrigatorio": false
        },
        "Content-Type": {
          "tipo": "string",
          "desc": "`application/json` ou `text/plain`.",
          "obrigatorio": true
        }
      },
      "corpo": {
        "v": {
          "tipo": "number",
          "desc": "Versão do lote: `1`.",
          "obrigatorio": true
        },
        "vid": {
          "tipo": "string",
          "desc": "Id aleatório deste navegador (UUID v4).",
          "obrigatorio": true
        },
        "sid": {
          "tipo": "string",
          "desc": "Id da sessão (30 min sem atividade encerram).",
          "obrigatorio": true
        },
        "sn": {
          "tipo": "number",
          "desc": "Número da sessão deste navegador.",
          "obrigatorio": true
        },
        "pv": {
          "tipo": "string",
          "desc": "Id da página vista.",
          "obrigatorio": true
        },
        "e": {
          "tipo": "object[]",
          "desc": "Até 40 eventos `{ t, n, p? }` do vocabulário do funil.",
          "obrigatorio": true
        }
      },
      "retorno": {
        "_texto": "202 sem corpo se guardado; 204 se ignorado. Sempre no-store."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/funil -H 'content-type: text/plain' -H 'x-mm-smoke: 1' -d '{\"v\":1,\"vid\":\"0f8b9c1e-2a3b-4c5d-8e6f-7a8b9c0d1e2f\",\"sid\":\"s1abcdefgh\",\"sn\":1,\"pv\":\"p1abcdefgh\",\"e\":[{\"t\":0,\"n\":\"pagina\"}]}'",
      "returns": "202 sem corpo se guardado; 204 se ignorado. Sempre no-store.",
      "url": "https://editalmd.com/api/funil",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/funil/arquivos",
      "auth": "none",
      "summary": "Operador: os dias do diário do funil guardados neste app, com o tamanho de cada um.",
      "grupo": "Operação",
      "headers": {
        "Authorization": {
          "tipo": "string",
          "desc": "`Bearer <METRICS_TOKEN>`.",
          "obrigatorio": true
        }
      },
      "retorno": {
        "v": {
          "tipo": "number",
          "desc": "Versão do lote guardado."
        },
        "produto": {
          "tipo": "string",
          "desc": "O produto."
        },
        "teto": {
          "tipo": "object",
          "desc": "`bytesDia` e `dias` guardados."
        },
        "dias": {
          "tipo": "object[]",
          "desc": "`{ dia, bytes }`, do mais velho ao de hoje."
        }
      },
      "erros": {
        "401": "Unauthorized",
        "503": "Not configured"
      },
      "exemplo": "curl -s $ORIGIN/api/funil/arquivos -H \"Authorization: Bearer $METRICS_TOKEN\"",
      "returns": "{ v, produto, teto, dias }",
      "url": "https://editalmd.com/api/funil/arquivos",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/funil/arquivo",
      "auth": "none",
      "summary": "Operador: um pedaço de um dia do diário do funil, em NDJSON, a partir de um byte.",
      "grupo": "Operação",
      "desc": "Até 4 MiB por resposta, cortados na última linha inteira. `X-MM-Funil-Proximo` diz de onde pedir o resto; `X-MM-Funil-Tamanho`, o tamanho do dia agora.",
      "headers": {
        "Authorization": {
          "tipo": "string",
          "desc": "`Bearer <METRICS_TOKEN>`.",
          "obrigatorio": true
        }
      },
      "query": {
        "dia": {
          "tipo": "string",
          "desc": "O dia, `AAAA-MM-DD` (UTC).",
          "obrigatorio": true
        },
        "desde": {
          "tipo": "number",
          "desc": "O byte de onde ler; `0` no começo.",
          "obrigatorio": false
        }
      },
      "retorno": {
        "_texto": "Linhas JSON, uma por lote guardado."
      },
      "erros": {
        "400": "Invalid parameters",
        "401": "Unauthorized",
        "503": "Not configured"
      },
      "exemplo": "curl -s \"$ORIGIN/api/funil/arquivo?dia=2026-09-27&desde=0\" -H \"Authorization: Bearer $METRICS_TOKEN\"",
      "returns": "Linhas JSON, uma por lote guardado.",
      "url": "https://editalmd.com/api/funil/arquivo",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/vitrine",
      "auth": "none",
      "grupo": "Números públicos",
      "summary": "Os números públicos do produto: tráfego, agentes, uso e confiabilidade, sem dinheiro.",
      "desc": "Projeção publicada de hora em hora pelo coletor da casa, arredondada a dois dígitos significativos; `null` é medição ausente, nunca zero. Cache de 15 minutos com ETag (`If-None-Match` → 304). Não há como enviar números por esta rota: a publicação é do coletor, com token próprio.",
      "retorno": {
        "v": {
          "tipo": "int",
          "desc": "Versão do contrato (1)."
        },
        "produto": {
          "tipo": "string",
          "desc": "Id do produto."
        },
        "publicado": {
          "tipo": "bool",
          "desc": "`false` antes da primeira publicação do coletor; aí só estas cinco chaves vêm."
        },
        "atualizado_em": {
          "tipo": "string",
          "desc": "Quando o coletor publicou (ISO 8601).",
          "nulo": true
        },
        "stale": {
          "tipo": "bool",
          "desc": "`true` quando a projeção tem mais de 26 h."
        },
        "nome": {
          "tipo": "string",
          "desc": "Nome do produto.",
          "opcional": true
        },
        "desde": {
          "tipo": "string",
          "desc": "Dia a partir do qual a série vale.",
          "nulo": true,
          "opcional": true
        },
        "fuso": {
          "tipo": "string",
          "desc": "Fuso dos dias de tráfego. A audiência informa seu próprio fuso em `pessoas.medicao`.",
          "opcional": true
        },
        "hoje": {
          "tipo": "object",
          "desc": "O dia de hoje: páginas por classe (pessoa, IA, bot), chamadas de API por classe, leituras das superfícies de máquina e uso do produto.",
          "opcional": true
        },
        "dias": {
          "tipo": "object[]",
          "desc": "Até 31 dias, o mais antigo primeiro: `dia`, `paginas`, `api`, `api_ia`, `maquina`, `visitantes`, `uso`.",
          "opcional": true
        },
        "janelas": {
          "tipo": "object",
          "desc": "Somas de 7 e 30 dias (`d7`, `d30`).",
          "opcional": true
        },
        "visitantes": {
          "tipo": "object",
          "desc": "Navegadores únicos com interação registrada, em 7 dias.",
          "opcional": true
        },
        "pessoas": {
          "tipo": "object",
          "desc": "Medição própria de navegadores confirmados por interação: únicos, sessões e páginas em 7 e 30 dias, recortes e cobertura. `null` indica ausência de medição. Não identifica pessoas verificadas.",
          "nulo": true,
          "opcional": true
        },
        "agentes": {
          "tipo": "object",
          "desc": "Os agentes de IA e os bots que mais leem, 7 dias.",
          "opcional": true
        },
        "superficies": {
          "tipo": "object",
          "desc": "Leituras de OKF, llms, well-known, OpenAPI e MCP em 7 dias.",
          "opcional": true
        },
        "mcp": {
          "tipo": "object",
          "desc": "Chamadas MCP em 7 dias.",
          "opcional": true
        },
        "uso": {
          "tipo": "object",
          "desc": "Uso real do produto por recurso: rótulo, hoje, 7 e 30 dias.",
          "opcional": true
        },
        "contas": {
          "tipo": "object",
          "desc": "Usuários e convidados.",
          "nulo": true,
          "opcional": true
        },
        "confiabilidade": {
          "tipo": "object",
          "desc": "Percentual de pedidos sem 5xx em 7 dias e o build no ar.",
          "opcional": true
        },
        "catalogo": {
          "tipo": "object",
          "desc": "Tamanho do acervo, quando o produto tem um.",
          "nulo": true,
          "opcional": true
        },
        "apoio": {
          "tipo": "object",
          "desc": "Apoios com medição: exposições por 1 s e cliques nativos por página em sessões confirmadas, CTR de 7 dias, dias observados e cobertura. Vazio é ausência de histórico, não CTR zero.",
          "opcional": true
        }
      },
      "exemplo": "curl -s $ORIGIN/api/vitrine",
      "returns": "{ v, produto, publicado, atualizado_em, stale, nome?, desde?, fuso?, hoje?, dias?, janelas?, visitantes?, pessoas?, agentes?, superficies?, mcp?, uso?, contas?, confiabilidade?, catalogo?, apoio? }",
      "url": "https://editalmd.com/api/vitrine",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/vitrine/operador",
      "auth": "none",
      "grupo": "Números públicos",
      "summary": "O documento completo do produto no painel do operador — só com o token do operador.",
      "headers": {
        "Authorization": {
          "tipo": "string",
          "desc": "`Bearer <METRICS_TOKEN>` — a classe operador.",
          "obrigatorio": true
        }
      },
      "retorno": {
        "produto": {
          "tipo": "string",
          "desc": "Id do produto."
        },
        "atualizado_em": {
          "tipo": "string",
          "desc": "Quando o coletor publicou.",
          "nulo": true
        },
        "operador": {
          "tipo": "object",
          "desc": "O documento completo do coletor, com o que a projeção pública não carrega.",
          "nulo": true
        }
      },
      "erros": {
        "401": "Sem token, token errado ou token de outra classe.",
        "503": "Worker sem `METRICS_TOKEN` ou sem o control plane."
      },
      "exemplo": "curl -s $ORIGIN/api/vitrine/operador -H \"Authorization: Bearer $METRICS_TOKEN\"",
      "returns": "{ produto, atualizado_em, operador }",
      "url": "https://editalmd.com/api/vitrine/operador",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/vitrine/painel",
      "auth": "none",
      "grupo": "Números públicos",
      "summary": "O painel da casa inteira, na forma que o gm lê — só com o token do operador.",
      "headers": {
        "Authorization": {
          "tipo": "string",
          "desc": "`Bearer <METRICS_TOKEN>` — a classe operador.",
          "obrigatorio": true
        }
      },
      "retorno": {
        "apps": {
          "tipo": "object[]",
          "desc": "Um documento do operador por produto, em ordem de id."
        },
        "updated": {
          "tipo": "string",
          "desc": "Quando o coletor fechou a rodada.",
          "opcional": true
        },
        "totals": {
          "tipo": "object",
          "desc": "Os totais da casa.",
          "opcional": true
        }
      },
      "erros": {
        "401": "Sem token, token errado ou token de outra classe.",
        "503": "Worker sem `METRICS_TOKEN` ou sem o control plane."
      },
      "exemplo": "curl -s $ORIGIN/api/vitrine/painel -H \"Authorization: Bearer $METRICS_TOKEN\"",
      "returns": "{ apps, updated?, totals? }",
      "url": "https://editalmd.com/api/vitrine/painel",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/vitrine/cursores",
      "auth": "none",
      "grupo": "Números públicos",
      "summary": "Cursores por produto: `borda`, `borda5xx` (só 5xx) e `cli`. Só com token do operador.",
      "headers": {
        "Authorization": {
          "tipo": "string",
          "desc": "`Bearer <METRICS_TOKEN>` — a classe operador.",
          "obrigatorio": true
        }
      },
      "retorno": {
        "_texto": "JSON: `{ [produto]: { borda?: ISO, borda5xx?: ISO, cli?: ISO } }`; vazio é `{}`."
      },
      "erros": {
        "401": "Sem token, token errado ou token de outra classe.",
        "503": "Worker sem `METRICS_TOKEN` ou sem o control plane."
      },
      "exemplo": "curl -s $ORIGIN/api/vitrine/cursores -H \"Authorization: Bearer $METRICS_TOKEN\"",
      "returns": "JSON: `{ [produto]: { borda?: ISO, borda5xx?: ISO, cli?: ISO } }`; vazio é `{}`.",
      "url": "https://editalmd.com/api/vitrine/cursores",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/partners",
      "auth": "none",
      "grupo": "Parceria",
      "summary": "Anúncios com preço fechado: espaços, duração, público e contratação. Parcerias e campanhas diferentes seguem por negociação.",
      "desc": "Quatro pacotes com preço em USD por semana, contratação avulsa ou assinatura semanal no cartão. Inclui canais reais, patrocinadores e números públicos. Contratação pelo POST /api/partners. Negociações e parcerias usam o contato. Cache de até 1 hora; com pedido vinculado, 1 minuto.",
      "retorno": {
        "status": {
          "tipo": "string",
          "desc": "`preco_fechado`: os espaços com preço podem ser contratados; os demais são negociados."
        },
        "produto": {
          "tipo": "string",
          "desc": "Nome do produto."
        },
        "idioma": {
          "tipo": "string",
          "desc": "Idioma dos textos (o do produto)."
        },
        "titulo": {
          "tipo": "string",
          "desc": "Título da oferta."
        },
        "descricao": {
          "tipo": "string",
          "desc": "Uma frase sobre a oferta."
        },
        "publico": {
          "tipo": "string",
          "desc": "Quem usa o produto — o público que o patrocinador alcança."
        },
        "modalidades": {
          "tipo": "object[]",
          "desc": "`{ id, nome }`: patrocinio, parceria, anuncio."
        },
        "placements": {
          "tipo": "object[]",
          "desc": "Canais incluídos nos pacotes: id, nome, onde, formato, medicao e disponivel. Preço mensal legado nulo no catálogo semanal."
        },
        "packages": {
          "tipo": "object[]",
          "desc": "Quatro pacotes: id, nome, assinatura, preco_usd_semana, espacos, canais e períodos permitidos em exposicao[{dias,preco}]."
        },
        "house_bundle": {
          "tipo": "object",
          "desc": "Indisponível no catálogo semanal: `{disponivel:false}`."
        },
        "parcerias": {
          "tipo": "string[]",
          "desc": "Ideias de parceria que o produto aceita discutir."
        },
        "current_sponsors": {
          "tipo": "object[]",
          "desc": "Patrocinadores em vigor: `id`, `nome`, `url`, `frase`, `espacos`, `ate`."
        },
        "stats": {
          "tipo": "object",
          "desc": "Recorte dos números públicos (`hoje`, `janelas`, `agentes`, `confiabilidade`) e o `link` para `/api/vitrine`; `publicado: false` antes da primeira publicação."
        },
        "payment": {
          "tipo": "object",
          "desc": "Pagamento compartilhado pelo POST da contratação. Os campos de carteira permanecem para compatibilidade; não envie pagamento manual antes da cotação."
        },
        "contact": {
          "tipo": "object",
          "desc": "`email`, `form_url`, `api_url` (`POST /api/contact`, livre: uma mensagem a cada 10 s por rede), `campos` (os obrigatórios), `campos_proposta` (os opcionais da proposta, com os valores aceitos de cada um), `message_template`, `instructions`."
        },
        "politica": {
          "tipo": "object",
          "desc": "Rótulo do espaço, setores recusados, pagamento adiantado, prazos."
        },
        "_links": {
          "tipo": "object",
          "desc": "`self`, `stats`, `page` (`null` até a página existir), `contact`, `casa` (o mesmo caminho nos dez produtos)."
        }
      },
      "exemplo": "curl -s $ORIGIN/api/partners",
      "returns": "{ status, produto, idioma, titulo, descricao, publico, modalidades, placements, packages, house_bundle, parcerias, current_sponsors, stats, payment, contact, politica, _links }",
      "url": "https://editalmd.com/api/partners",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/partners",
      "auth": "none",
      "grupo": "Parceria",
      "summary": "Contrate um pacote semanal de anúncios e envie a arte para revisão.",
      "desc": "O servidor calcula o preço do pacote e das semanas. Avulso: cotação 402 e pagamento compartilhado, sem renovação. modalidade=assinatura: conta autenticada, CSRF da mesma origem, cartão nativo e aceite explícito da renovação semanal. Consulte a oferta atual em BRL em /api/credito/assinaturas/ofertas. Cancele as próximas cobranças na conta. modalidade=recibo consulta apenas o recibo da campanha da própria conta. A cobrança precede a revisão; a exibição começa na publicação. Repetições mantêm id, token e conteúdo. A cotação não grava arte nem reserva espaço. Campanhas diferentes e parcerias gratuitas usam POST /api/contact.",
      "query": [
        {
          "nome": "modalidade",
          "tipo": "string",
          "desc": "Omit for one-off payment; assinatura uses native weekly card billing; recibo reads the account's campaign receipt."
        }
      ],
      "corpo": {
        "id": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Fresh random order id: 32 lowercase hexadecimal characters. Reuse for retries."
        },
        "token": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Private random order capability: 64 lowercase hexadecimal characters. Keep it for recovery."
        },
        "espaco": {
          "tipo": "string[]",
          "desc": "Legacy paid-order retry only. New purchases select a package."
        },
        "pacote": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "One of the four package ids in GET /api/partners packages."
        },
        "duracao": {
          "tipo": "int",
          "obrigatorio": true,
          "desc": "Days from the package exposure list. Weekly subscriptions require 7."
        },
        "assinatura": {
          "tipo": "object",
          "desc": "Only with modalidade=assinatura: the native subscription body with recurso=publicidade:ORDER_ID, simulado, cartao and explicit renewal aceite. The authenticated account must own the campaign."
        },
        "pedido": {
          "tipo": "string",
          "desc": "Only with modalidade=recibo: the campaign id owned by the signed-in account."
        },
        "nome": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Brand or product, up to 80 characters."
        },
        "email": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Contact email."
        },
        "url": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "HTTPS destination URL."
        },
        "frase": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Ad copy, up to 100 characters."
        },
        "arte": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Base64 image bytes, without a data URL prefix. PNG, JPEG or WebP, up to 2 MB."
        },
        "direitos": {
          "tipo": "bool",
          "obrigatorio": true,
          "desc": "true confirms the right to use the image and content."
        }
      },
      "retorno": {
        "id": {
          "tipo": "string",
          "desc": "Order id."
        },
        "estado": {
          "tipo": "string",
          "desc": "revisao: paid and awaiting content approval."
        },
        "recibo": {
          "tipo": "string",
          "desc": "Verified payment receipt."
        }
      },
      "erros": {
        "400": "Invalid order or artwork.",
        "402": "Payment required.",
        "409": "Space occupied or order changed.",
        "503": "Checkout unavailable."
      },
      "exemplo": "curl -X POST '$ORIGIN/api/partners' -H 'content-type: application/json' -H 'Idempotency-Key: ORDER_ID' --data-binary @campaign.json",
      "returns": "{ id, estado, recibo }",
      "url": "https://editalmd.com/api/partners",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/newsletter",
      "auth": "session",
      "grupo": "Conta",
      "summary": "Consulte a autorização de publicidade por e-mail.",
      "desc": "Somente a conta da sessão. Não recebe identificador de outra conta. Resposta sem cache.",
      "retorno": {
        "ativo": {
          "tipo": "bool",
          "desc": "Autorização separada para publicidade."
        },
        "areas": {
          "tipo": "string[]",
          "desc": "[\"publicidade\"]."
        },
        "idioma": {
          "tipo": "string",
          "desc": "pt | en."
        },
        "verificado": {
          "tipo": "bool",
          "desc": "A conta tem e-mail confirmado."
        }
      },
      "erros": {
        "401": "invalid_session",
        "503": "newsletter_indisponivel"
      },
      "exemplo": "curl -s \"$ORIGIN/api/newsletter\" -b \"$COOKIE\"",
      "returns": "{ ativo, areas, idioma, verificado }",
      "url": "https://editalmd.com/api/newsletter",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "PUT",
      "path": "/api/newsletter",
      "auth": "session",
      "grupo": "Conta",
      "summary": "Autorize ou pare publicidade nos avisos solicitados.",
      "desc": "Exige sessão, origem e X-CSRF-Token. Ativar exige consentimento explícito e e-mail confirmado. Retirar é imediato e preserva avisos essenciais. Até uma publicidade por conta a cada 24 horas.",
      "headers": {
        "X-CSRF-Token": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Valor CSRF fornecido pelo SDK."
        }
      },
      "corpo": {
        "ativo": {
          "tipo": "bool",
          "obrigatorio": true,
          "desc": "true autoriza; false retira."
        },
        "areas": {
          "tipo": "string[]",
          "obrigatorio": true,
          "desc": "[\"publicidade\"]."
        },
        "idioma": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Idioma dos avisos: pt ou en."
        },
        "consentimento": {
          "tipo": "bool",
          "desc": "true ao autorizar."
        }
      },
      "body": {
        "ativo": false,
        "areas": [
          "publicidade"
        ],
        "idioma": "en"
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "true."
        },
        "ativo": {
          "tipo": "bool",
          "desc": "Autorização separada para publicidade."
        },
        "areas": {
          "tipo": "string[]",
          "desc": "[\"publicidade\"]."
        },
        "idioma": {
          "tipo": "string",
          "desc": "pt | en."
        }
      },
      "erros": {
        "400": "assinatura_invalida",
        "401": "invalid_session",
        "403": "invalid_csrf | email_verificado_exigido",
        "429": "aguarde_para_alterar | limite_diario",
        "503": "newsletter_indisponivel"
      },
      "exemplo": "curl -X PUT \"$ORIGIN/api/newsletter\" -b \"$COOKIE\" -H \"Origin: $ORIGIN\" -H \"X-CSRF-Token: $CSRF\" -H \"Content-Type: application/json\" -d '{\"ativo\":false,\"areas\":[\"publicidade\"],\"idioma\":\"en\"}'",
      "returns": "{ ok, ativo, areas, idioma }",
      "url": "https://editalmd.com/api/newsletter",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "POST",
      "path": "/api/newsletter/cancelar",
      "auth": "none",
      "grupo": "Conta",
      "summary": "Retire a autorização pelo link recebido no e-mail.",
      "desc": "O token secreto do link substitui a sessão. JSON exige a origem do produto. Também aceita RFC 8058: corpo List-Unsubscribe=One-Click e token na query, sem login. Avisos essenciais continuam.",
      "corpo": {
        "token": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Token de 43 caracteres do link, sem o prefixo."
        }
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "true."
        }
      },
      "erros": {
        "400": "cancelamento_invalido | confirmacao_exigida",
        "403": "invalid_origin",
        "404": "cancelamento_invalido_ou_vencido"
      },
      "exemplo": "curl \"$ORIGIN/api/newsletter/cancelar\" -H \"Origin: $ORIGIN\" -H \"Content-Type: application/json\" -d '{\"token\":\"<link-token>\"}'",
      "returns": "{ ok }",
      "url": "https://editalmd.com/api/newsletter/cancelar",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/metrics",
      "auth": "none",
      "summary": "Métricas dos últimos 7 dias para o painel do operador; com o token, inclui os pagamentos.",
      "grupo": "Operação",
      "desc": "Sem credencial devolve visitas, uso (entregas de markdown, alertas, vigias). Com `METRICS_TOKEN` em Bearer acrescenta `payments` — só x402 liquidado em Base mainnet.",
      "headers": {
        "Authorization": {
          "tipo": "string",
          "desc": "`Bearer <METRICS_TOKEN>` para incluir o bloco financeiro; token errado é 401.",
          "obrigatorio": false
        }
      },
      "retorno": "Metricas",
      "erros": {
        "401": "Token de operador errado.",
        "503": "Worker sem METRICS_TOKEN configurado."
      },
      "exemplo": "curl -s $ORIGIN/api/metrics -H \"Authorization: Bearer $METRICS_TOKEN\"",
      "returns": "{ app, today, today_visits, today_contacts?, days, usage, accounts, financeiro?, payments? }",
      "url": "https://editalmd.com/api/metrics",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/recibo/:id",
      "auth": "none",
      "summary": "Recibo de uma entrega — a prova de o que saiu, quanto custou e com qual hash.",
      "grupo": "Prova",
      "params": {
        "id": {
          "desc": "Identificador do recibo (32 hex), do header `x-editalmd-recibo`.",
          "exemplo": "0c8f2b…"
        }
      },
      "retorno": {
        "recibo": {
          "tipo": "Recibo",
          "desc": "O recibo."
        }
      },
      "erros": {
        "404": "Recibo não encontrado."
      },
      "exemplo": "curl -s $ORIGIN/api/recibo/0c8f…",
      "returns": "{ recibo{id,recurso,documento_id,preco_usd,modo,sha256_entregue,bytes,criado_em} }",
      "url": "https://editalmd.com/api/recibo/:id",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/atas",
      "auth": "none",
      "summary": "Atas de registro de preço vigentes pelo objeto, com a vigência e se aceitam adesão. Grátis.",
      "grupo": "Acervo",
      "desc": "Busca as atas de registro de preço publicadas no PNCP que ainda valem (não canceladas, vigência até hoje ou depois), as mais relevantes para os termos primeiro: o órgão gerenciador, o objeto, a vigência, se aceita adesão (a carona) e o endereço da ata no PNCP. `adesao=1` traz só as que aceitam. A ficha da compra (`/api/compra/:id`) traz as atas que ela gerou. `Accept: text/html` abre a aba Preços registrados com os termos.",
      "query": {
        "q": {
          "tipo": "string",
          "desc": "Termos do objeto ou do item, mínimo 3 letras.",
          "obrigatorio": true
        },
        "pagina": {
          "tipo": "int",
          "desc": "Página, 0 a 49 (padrão 0)."
        },
        "adesao": {
          "tipo": "string",
          "desc": "`1`: só as atas que aceitam adesão."
        }
      },
      "retorno": "AtasVigentes",
      "erros": {
        "400": "Termo curto: `termo_curto`, com `minimo_caracteres`.",
        "502": "Origem indisponível.",
        "503": "Base em carga (`base_indisponivel`) ou busca demorada, com `Retry-After`."
      },
      "exemplo": "curl -s '$ORIGIN/api/atas?q=papel%20a4&adesao=1'",
      "returns": "{ itens[{ata,compra,atas,compra_id?,numero,orgao,orgao_cnpj,unidade,objeto,vigencia_inicio,vigencia_fim,adesao,pncp_url}], pagina, mais, fonte }",
      "url": "https://editalmd.com/api/atas",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/planos",
      "auth": "none",
      "summary": "O que os órgãos planejam comprar: itens dos planos de contratações anuais, antes da licitação. Grátis.",
      "grupo": "Acervo",
      "desc": "Busca os itens dos planos de contratações anuais (PCA) que os órgãos publicam no PNCP: o que cada um pretende comprar, quanto, por quanto e para quando — a demanda antes de a licitação abrir. Só a versão em vigor de cada plano; sem `ano`, do ano corrente em diante. Para saber quando a licitação abrir, crie um alerta com os mesmos termos (`/api/alertas`). `Accept: text/html` abre a aba Compras previstas com os termos.",
      "query": {
        "q": {
          "tipo": "string",
          "desc": "Termos do objeto ou do item, mínimo 3 letras.",
          "obrigatorio": true
        },
        "pagina": {
          "tipo": "int",
          "desc": "Página, 0 a 49 (padrão 0)."
        },
        "ano": {
          "tipo": "int",
          "desc": "Ano do plano (opcional)."
        }
      },
      "retorno": "PlanosDeCompras",
      "erros": {
        "400": "Termo curto: `termo_curto`, com `minimo_caracteres`.",
        "502": "Origem indisponível.",
        "503": "Base em carga (`base_indisponivel`) ou busca demorada, com `Retry-After`."
      },
      "exemplo": "curl -s '$ORIGIN/api/planos?q=notebook'",
      "returns": "{ itens[{plano,item,ano,descricao,categoria,classe,unidade_fornecimento,quantidade,valor_unitario,valor_total,data_desejada,orgao,orgao_cnpj,unidade}], pagina, mais, fonte }",
      "url": "https://editalmd.com/api/planos",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/estaduais",
      "auth": "none",
      "summary": "Licitações fora do PNCP, do tribunal de contas do estado ou do portal da entidade (hoje TCE-RS, TCE-PE, TCE-RN, TCM-PA, Sebrae e Sanepar). Grátis.",
      "grupo": "Acervo",
      "desc": "Busca as licitações que os órgãos informam ao tribunal de contas do estado, ou publicam no próprio portal, e que não estão no PNCP, as mais relevantes para os termos primeiro: o órgão, o município, a modalidade, a abertura, os valores e o endereço da licitação na página da fonte, com os documentos. As fontes de hoje são o LicitaCon do TCE-RS, os dados abertos do TCE-PE e do TCE-RN, o mural de licitações do TCM-PA, o Canal do Fornecedor do Sebrae e o Sistema de Licitações da Sanepar (os cinco últimos só com as licitações em andamento), conferidas a cada 6 h. `abertas=1` traz só as que abrem de hoje em diante. A licitação que também está no PNCP sai em `/api/busca`. `Accept: text/html` abre a aba Fora do PNCP com os termos.",
      "query": {
        "q": {
          "tipo": "string",
          "desc": "Termos do objeto ou do item, mínimo 3 letras.",
          "obrigatorio": true
        },
        "pagina": {
          "tipo": "int",
          "desc": "Página, 0 a 49 (padrão 0)."
        },
        "uf": {
          "tipo": "string",
          "desc": "UF do órgão, duas letras (opcional)."
        },
        "abertas": {
          "tipo": "string",
          "desc": "`1`: só as licitações com abertura de hoje em diante."
        }
      },
      "retorno": "LicitacoesEstaduais",
      "erros": {
        "400": "Termo curto (`termo_curto`, com `minimo_caracteres`) ou UF inválida (`uf_invalida`).",
        "502": "Origem indisponível.",
        "503": "Base em carga (`base_indisponivel`) ou busca demorada, com `Retry-After`."
      },
      "exemplo": "curl -s '$ORIGIN/api/estaduais?q=merenda%20escolar&uf=RS'",
      "returns": "{ itens[{fonte,fonte_nome,origem,tribunal,chave,uf,orgao,orgao_cnpj,municipio,numero,ano,processo,modalidade_id,modalidade_codigo,modalidade_nome,objeto,valor_estimado,valor_homologado,abertura,homologacao,vencedor_cnpj,url}], pagina, mais, fonte }",
      "url": "https://editalmd.com/api/estaduais",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/plans",
      "auth": "none",
      "summary": "The plans for sale and the authenticated account or wallet's active plan.",
      "desc": "Pix and USDC pay 30 days with no automatic renewal; the card subscribes monthly and renews until you cancel. Without an account or wallet credential, `account` is `null`. Original PDFs are free. An active plan includes usage.total, usage.used and usage.remaining. One page uses 1 unit, a price report 25, an alert 5 and a tender watch 3. Allowance is consumed before prepaid credit.",
      "grupo": "Billing",
      "query": {
        "resumo": {
          "tipo": "string",
          "obrigatorio": false,
          "desc": "Use `1` to read the active plan without cancellation, retention and refund details.",
          "exemplo": "1"
        }
      },
      "retorno": {
        "plans": {
          "tipo": "object[]",
          "desc": "Each plan: `id`, `name`, `document_pages`, `days`, `price_usd`, `automatic_renewal`, `charged_now` and the `buy` URL."
        },
        "account": {
          "tipo": "object",
          "desc": "`active` (the plan that ends last, with `valid_until`) and `cancel` (what cancelling removes when the plan ends, the free-days offer, the refund, `keeps_until`, until when what you paid for stays active, `ends_now`, true when cancelling ends part of the plan now, and `renews`, true when a monthly subscription renews it). Without a refund, `ends_now` or `renews`, cancelling changes nothing.",
          "nulo": true
        }
      },
      "erros": {
        "401": "session_ended",
        "503": "auth_unavailable"
      },
      "exemplo": "curl -s $ORIGIN/api/plans",
      "returns": "{ plans, account }",
      "url": "https://editalmd.com/api/plans",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/plans/:plan",
      "auth": "none",
      "summary": "Buys a plan for the account or paying wallet.",
      "desc": "Pix and USDC pay 30 days with no automatic renewal; the card subscribes monthly and renews until you cancel. Without payment, the answer is 402 with the price. Pay with prepaid credit (`X-Credito`) or x402 (`PAYMENT-SIGNATURE` v2 or `X-PAYMENT` v1). Without an account, the verified paying wallet owns the purchase. Use wallet agent authentication to read its plan, or claim it after account sign-in. The `compra` mark prevents repeat credit debits. An x402 nonce can settle only once; keep the receipt after a delivery error. Original PDFs are free. An active plan includes usage.total, usage.used and usage.remaining. One page uses 1 unit, a price report 25, an alert 5 and a tender watch 3. Allowance is consumed before prepaid credit.",
      "grupo": "Billing",
      "params": {
        "plan": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "`pro-paginas` (1000 shared allowance units), `profissional-paginas` (10000 shared allowance units), `empresarial-paginas` (100000 shared allowance units)",
          "exemplo": "pro-paginas"
        }
      },
      "query": {
        "compra": {
          "tipo": "string",
          "obrigatorio": false,
          "desc": "Mark of one credit purchase, 8 to 64 letters, digits, `-` or `_`. Repeating it with the same credit token does not debit again.",
          "exemplo": "purchase-2026-10-12"
        }
      },
      "retorno": {
        "plan": {
          "tipo": "string",
          "desc": "The plan bought."
        },
        "document_pages_added": {
          "tipo": "number",
          "desc": "Units granted by this purchase."
        },
        "valid_until": {
          "tipo": "string",
          "desc": "When this purchase ends (ISO 8601)."
        },
        "automatic_renewal": {
          "tipo": "bool",
          "desc": "`false` for Pix, USDC and credit."
        },
        "account": {
          "tipo": "object",
          "desc": "The active plan for the owner; `null` if its summary is unavailable.",
          "nulo": true
        },
        "_links": {
          "tipo": "object",
          "desc": "Plans URL and, for a wallet purchase, wallet authentication and claim URLs."
        }
      },
      "erros": {
        "401": "An explicit account, wallet or credit credential was refused.",
        "402": "Payment required: the price and the accepted payments.",
        "403": "Writes with the account cookie need the same Origin and `X-CSRF-Token`.",
        "404": "Unknown plan (`unknown_plan`).",
        "409": "Plans are not on sale now (`sales_closed`) or billing is off (`billing_off`)."
      },
      "exemplo": "curl -s -X POST \"$ORIGIN/api/plans/pro-paginas?compra=purchase-2026-10-12\" -H \"X-CSRF-Token: $CSRF\" -H \"X-Credito: $CREDITO\" -b \"$COOKIE\"",
      "returns": "{ plan, document_pages_added, valid_until, automatic_renewal, account, _links }",
      "url": "https://editalmd.com/api/plans/:plan",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/plans/cancel",
      "auth": "session",
      "summary": "Cancels the active plan: nothing else is charged, and what you paid for stays active until the end of its period.",
      "desc": "Send `{ \"accept_data_removal\": true }`. The monthly card subscription stops. A purchase made less than 7 days ago and a paid period that has not started yet, such as a renewal, go back the same way they were paid (card or Pix) and end now. The rest of the paid period stays active until `keeps_until`; then what the plan added ends (`account.cancel.losses` in `GET /api/plans` says what). A purchase paid with USDC or with credit from another purchase stays active until its end; ask for its refund by e-mail, as the cancellation page says. Original PDFs are free. An active plan includes usage.total, usage.used and usage.remaining. One page uses 1 unit, a price report 25, an alert 5 and a tender watch 3. Allowance is consumed before prepaid credit.",
      "grupo": "Billing",
      "corpo": {
        "accept_data_removal": {
          "tipo": "bool",
          "obrigatorio": true,
          "desc": "Must be `true`: you accept losing what the plan added."
        }
      },
      "body": {
        "accept_data_removal": true
      },
      "retorno": {
        "canceled": {
          "tipo": "bool",
          "desc": "`true` when a valid plan was canceled: it ended now, or it stays active until `keeps_until`."
        },
        "refund": {
          "tipo": "object",
          "desc": "`method` (`original`), `amount_cents` and its `currency` (`brl` when Asaas refunds, `usd` when Stripe refunds; `null` when both do).",
          "nulo": true
        },
        "keeps_until": {
          "tipo": "string",
          "desc": "When the paid period that stays active ends (ISO 8601); `null` when everything ended now.",
          "nulo": true
        },
        "account": {
          "tipo": "object",
          "desc": "The account state after cancelling, as in `GET /api/plans`."
        }
      },
      "erros": {
        "400": "Missing `accept_data_removal: true` (`confirmation_required`).",
        "401": "Sign in first (`account_required`), or the session ended (`session_ended`).",
        "403": "Writes with the account cookie need the same Origin and `X-CSRF-Token`."
      },
      "exemplo": "curl -s -X POST $ORIGIN/api/plans/cancel -H \"Content-Type: application/json\" -H \"X-CSRF-Token: $CSRF\" -b \"$COOKIE\" -d '{\"accept_data_removal\":true}'",
      "returns": "{ canceled, refund, keeps_until, account }",
      "url": "https://editalmd.com/api/plans/cancel",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "POST",
      "path": "/api/plans/:plan/grace",
      "auth": "session",
      "summary": "Takes the free-days offer from the cancellation: the offered plan, free for 7 days, once per account.",
      "desc": "`account.cancel.offer` in `GET /api/plans` says which plan and for how long. Nothing renews by itself, and what you paid for stays active until its end; the free days start after it. Original PDFs are free. An active plan includes usage.total, usage.used and usage.remaining. One page uses 1 unit, a price report 25, an alert 5 and a tender watch 3. Allowance is consumed before prepaid credit.",
      "grupo": "Billing",
      "params": {
        "plan": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "`pro-paginas` (1000 shared allowance units), `profissional-paginas` (10000 shared allowance units), `empresarial-paginas` (100000 shared allowance units)",
          "exemplo": "pro-paginas"
        }
      },
      "retorno": {
        "plan": {
          "tipo": "string",
          "desc": "The plan granted."
        },
        "valid_until": {
          "tipo": "string",
          "desc": "When the free days end."
        },
        "price_usd": {
          "tipo": "number",
          "desc": "Always `0`."
        },
        "account": {
          "tipo": "object",
          "desc": "The account state after the offer, as in `GET /api/plans`."
        }
      },
      "erros": {
        "401": "Sign in first (`account_required`), or the session ended (`session_ended`).",
        "403": "Writes with the account cookie need the same Origin and `X-CSRF-Token`.",
        "404": "Unknown plan (`unknown_plan`).",
        "409": "No offer for this account or plan (`offer_unavailable`)."
      },
      "exemplo": "curl -s -X POST $ORIGIN/api/plans/pro-paginas/grace -H \"X-CSRF-Token: $CSRF\" -b \"$COOKIE\"",
      "returns": "{ plan, valid_until, price_usd, account }",
      "url": "https://editalmd.com/api/plans/:plan/grace",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "path": "/api/acesso",
      "auth": "none",
      "grupo": "API access",
      "retorno": "ApiAccess",
      "method": "GET",
      "summary": "Discover the monthly data package or inspect a private purchase.",
      "headers": {
        "X-API-Pass": {
          "tipo": "string",
          "desc": "Private pass: api_<32 random hex>_<64 random hex>. Save before buying."
        }
      },
      "erros": {
        "400": "Invalid pass.",
        "404": "Unknown purchase or wrong owner.",
        "503": "Purchases disabled."
      },
      "exemplo": "curl -s $ORIGIN/api/acesso",
      "returns": "{ offer{id,price_usd,credits,days,auto_renew,unit,products,purchase,method,status,header,payment_methods,prepaid_credit,instructions,generate_pass,client,guide,workflow,evaluation}, enabled?, id?, status?, granted_credits?, expires_at?, receipt?, via?, message? }",
      "url": "https://editalmd.com/api/acesso",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "path": "/api/acesso",
      "auth": "none",
      "grupo": "API access",
      "retorno": "ApiAccess",
      "method": "POST",
      "summary": "Buy 1000 basic data reads for US$1, valid for 30 days.",
      "preco_usd": 1,
      "desc": "Same pass in retries recovers the same purchase. No automatic renewal. OCR, AI, documents and delivery keep their own tariffs. Send X-API-Pass on eligible data reads; remaining credits come in X-API-Credits-Remaining. With prepaid credit, you can skip this purchase: send X-Credito (or Authorization: Bearer cred_…) on the data read, and after the free allowance the origin buys these packages from the credit, one at a time.",
      "headers": {
        "X-API-Pass": {
          "tipo": "string",
          "desc": "Private pass: api_<32 random hex>_<64 random hex>. Save before buying.",
          "obrigatorio": true
        },
        "X-Credito": {
          "tipo": "string",
          "desc": "Existing prepaid credit token; alternative to x402."
        },
        "Authorization": {
          "tipo": "string",
          "desc": "Bearer cred_… alternative to X-Credito."
        },
        "X-PAYMENT": {
          "tipo": "string",
          "desc": "Signed x402 authorization from the 402 quote, maximum 16 KiB."
        },
        "PAYMENT-SIGNATURE": {
          "tipo": "string",
          "desc": "Alternative name for X-PAYMENT."
        },
        "X-API-Transaction": {
          "tipo": "string",
          "desc": "Confirmed Base transaction hash for reconciliation with the original pass and signed payment. Never creates another charge."
        }
      },
      "erros": {
        "400": "Missing or invalid pass/payment.",
        "401": "Invalid prepaid credit.",
        "402": "Payment required: x402 accepts[] and prepaid-credit instructions.",
        "409": "Payment pending; retain the same pass and do not pay again.",
        "429": "Purchase attempt limit; respect Retry-After.",
        "503": "Payment unavailable or pending reconciliation."
      },
      "exemplo": "curl -s -X POST \"$ORIGIN/api/acesso\" -H \"X-API-Pass: $API_PASS\"",
      "returns": "{ offer{id,price_usd,credits,days,auto_renew,unit,products,purchase,method,status,header,payment_methods,prepaid_credit,instructions,generate_pass,client,guide,workflow,evaluation}, enabled?, id?, status?, granted_credits?, expires_at?, receipt?, via?, message? }",
      "url": "https://editalmd.com/api/acesso",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/consulta/cadastro/:cnpj",
      "auth": "none",
      "grupo": "Consulta de CNPJ, sanções e endereço",
      "summary": "Ficha cadastral gratuita: nome, situação, atividade e endereço.",
      "desc": "Não consome franquia nem saldo. Não revela contatos ou sócios e não executa análise adicional. Mantém o limite de proteção da origem. Para sanções, situação fiscal e CNIA ao vivo, peça explicitamente /api/consulta/cnpj/:cnpj.",
      "params": {
        "cnpj": {
          "desc": "CNPJ com ou sem pontuação.",
          "exemplo": "66300125000145"
        }
      },
      "retorno": "ConsultaCadastro",
      "erros": {
        "400": "CNPJ ou CEP inválido.",
        "404": "Registro não encontrado.",
        "429": "Limite de proteção da origem. Aguarde o Retry-After, sem cobrança.",
        "503": "Fonte indisponível. Tente novamente, sem cobrança."
      },
      "exemplo": "curl -s '$ORIGIN/api/consulta/cadastro/66300125000145'",
      "returns": "{ consulta, escopo, cnpj, empresa }",
      "url": "https://editalmd.com/api/consulta/cadastro/:cnpj",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/consulta/endereco/:cep",
      "auth": "none",
      "grupo": "Consulta de CNPJ, sanções e endereço",
      "summary": "Endereços e empresas de um CEP, sem consumir franquia nem saldo.",
      "desc": "Até 20 endereços e 20 empresas. pontos_total informa o total; escopo=cadastro. Sem uso nem _links. Mantém o limite de proteção da origem.",
      "params": {
        "cep": {
          "desc": "CEP com ou sem hífen.",
          "exemplo": "71915000"
        }
      },
      "retorno": "ConsultaEndereco",
      "erros": {
        "400": "CNPJ ou CEP inválido.",
        "404": "Registro não encontrado.",
        "429": "Limite de proteção da origem. Aguarde o Retry-After, sem cobrança.",
        "503": "Fonte indisponível. Tente novamente, sem cobrança."
      },
      "exemplo": "curl -s '$ORIGIN/api/consulta/endereco/71915000'",
      "returns": "{ consulta, escopo, cep, endereco, pontos, pontos_total, empresas{itens,mais}, fonte }",
      "url": "https://editalmd.com/api/consulta/endereco/:cep",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/consulta/cep/:cep",
      "auth": "none",
      "grupo": "Consulta de CNPJ, sanções e endereço",
      "summary": "Consulta um endereço pelo CEP, grátis: os endereços com coordenada (CNEFE/IBGE) e as empresas registradas nele.",
      "desc": "O nome antigo de `GET /api/consulta/endereco/:cep`, com o mesmo resultado: não consome franquia nem saldo. Devolve até 20 endereços e até 20 empresas; o total de endereços vem em `pontos_total`.",
      "params": {
        "cep": {
          "desc": "CEP com ou sem hífen.",
          "exemplo": "01310100"
        }
      },
      "retorno": "ConsultaEndereco",
      "erros": {
        "400": "CNPJ ou CEP inválido.",
        "404": "Registro não encontrado.",
        "429": "Limite de proteção da origem. Aguarde o Retry-After, sem cobrança.",
        "503": "Fonte indisponível. Tente novamente, sem cobrança."
      },
      "exemplo": "curl -s '$ORIGIN/api/consulta/cep/01310100'",
      "returns": "{ consulta, escopo, cep, endereco, pontos, pontos_total, empresas{itens,mais}, fonte }",
      "url": "https://editalmd.com/api/consulta/cep/:cep",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/consulta/sugerir",
      "auth": "none",
      "grupo": "Consulta de CNPJ, sanções e endereço",
      "summary": "Sugere empresas por CNPJ, nome, sócio, telefone ou e-mail, sem seletor.",
      "desc": "Até 8 empresas, ordenadas por correspondência. Não consome consultas nem revela contatos. Incompleto indica que uma das fontes não respondeu.",
      "query": {
        "q": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Nome com 3 a 120 caracteres, CNPJ, telefone com DDD ou e-mail completo.",
          "exemplo": "wrp consultoria"
        }
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Verdadeiro quando ao menos uma fonte respondeu."
        },
        "incompleto": {
          "tipo": "bool",
          "desc": "Verdadeiro quando alguma fonte de sugestão falhou."
        },
        "results": {
          "tipo": "object[]",
          "desc": "Até 8 empresas sem repetição: cnpj, label e correspondencia. A busca textual pode incluir razaoSocial, municipio, bairro, uf, situacao, situacaoEspecial e perto. Sem contatos ou nomes pessoais."
        }
      },
      "erros": {
        "400": "Termo incompleto ou inválido.",
        "429": "Limite da origem.",
        "503": "Busca indisponível."
      },
      "exemplo": "curl -s '$ORIGIN/api/consulta/sugerir?q=wrp%20consultoria'",
      "returns": "{ ok, incompleto, results }",
      "url": "https://editalmd.com/api/consulta/sugerir",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/consulta",
      "auth": "none",
      "grupo": "Consulta de CNPJ, sanções e endereço",
      "summary": "O serviço de consulta de CNPJ e endereço: a franquia grátis de hoje, o pacote avulso, os três planos e o seu saldo.",
      "desc": "Sem credencial mostra a franquia e as ofertas. Com conta, crédito (`X-Credito`) ou carteira x402 (`X-Wallet-Token`), mostra também o saldo compartilhado entre Radar CNPJ, PontoFato e EditalMD. A credencial da carteira é emitida separadamente em cada portal.",
      "query": {
        "lingua": {
          "tipo": "string",
          "desc": "Língua das mensagens: `pt` ou `en` (padrão: a do navegador, senão inglês).",
          "valores": [
            "pt",
            "en"
          ]
        }
      },
      "headers": {
        "X-Wallet-Token": {
          "tipo": "string",
          "obrigatorio": false,
          "desc": "Credencial mmw_… deste portal, obtida pela assinatura da carteira em /api/auth/wallet/agent/start e /api/auth/wallet/agent/token. Autoriza o uso do saldo da carteira x402."
        }
      },
      "retorno": "ConsultaServico",
      "erros": {
        "401": "Credencial apresentada e recusada.",
        "503": "Serviço de conta ou de saldo fora do ar."
      },
      "exemplo": "curl -s '$ORIGIN/api/consulta?lingua=pt'",
      "returns": "{ servico, nome, descricao, gratis{por_dia,restantes_hoje,renova_em?}, ofertas[{id,tipo,nome,consultas,dias,renovacao_automatica,preco_usd,preco_brl,disponivel,compra}], lote, saldo{dono,consultas,planos}, como_comprar, _links }",
      "url": "https://editalmd.com/api/consulta",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/consulta/cnpj/:cnpj",
      "auth": "none",
      "grupo": "Consulta de CNPJ, sanções e endereço",
      "summary": "Consulta adicional de CNPJ: registros públicos preparados e opção de exigir conferência do CNIA durante o pedido.",
      "desc": "Use cnia_atual=true para exigir consultar a fonte do CNIA neste pedido. Se falhar, retorna 503 sem cobrança e sem recorrer ao resultado anterior. Sem essa exigência, pode vir o CNIA guardado; confira conferidoEm. As outras bases conservam suas datas. A consulta usa a franquia diária disponível e depois o saldo ou a cotação por chamada. CNPJ ausente, fonte indisponível ou limite da origem não são cobrados. Os dados pessoais ficam mascarados. As sanções são agregadas pela raiz do CNPJ.",
      "params": {
        "cnpj": {
          "desc": "CNPJ com ou sem pontuação (14 caracteres).",
          "exemplo": "00000000000191"
        }
      },
      "query": {
        "lingua": {
          "tipo": "string",
          "desc": "Língua das mensagens: `pt` ou `en` (padrão: a do navegador, senão inglês).",
          "valores": [
            "pt",
            "en"
          ]
        },
        "temas": {
          "tipo": "string",
          "desc": "Temas separados por vírgula (até 240 caracteres): dados, contagens, socios, sancoes, fiscal, divida, obras, trabalho, ibama, contratos, pep, vendas, campanhas, prefeituras, sicaf, aeronaves, fundos, rntrc, bndes, registros; todos. Sem o parâmetro, mantém a ficha completa. O cadastro básico sempre vem; sócios só com socios. contagens acrescenta ao cadastro o objeto contagens, só com os números da ficha: socios, pep, sancoes, fiscal, socioambiental, governo e registros. Campos não solicitados são omitidos; null significa fonte não conferida. SICAF, aeronaves e RNTRC recortam registros por órgão; registros inclui todos os órgãos. Não muda preço, limites nem máscara de dados pessoais.",
          "exemplo": "sicaf,contratos,bndes"
        },
        "cnia_atual": {
          "tipo": "bool",
          "desc": "true exige consultar o CNIA durante este pedido. Se a fonte falhar, retorna 503 sem cobrar e sem usar o registro anterior. Padrão false. Com temas, inclua sancoes.",
          "padrao": false
        }
      },
      "headers": {
        "Idempotency-Key": {
          "tipo": "string",
          "obrigatorio": false,
          "desc": "Chave da tentativa (até 80 caracteres). A mesma empresa, no mesmo dia de Brasília e com o mesmo titular, não desconta o saldo de novo, com ou sem esta chave."
        },
        "X-Wallet-Token": {
          "tipo": "string",
          "obrigatorio": false,
          "desc": "Credencial mmw_… deste portal, obtida pela assinatura da carteira em /api/auth/wallet/agent/start e /api/auth/wallet/agent/token. Autoriza o uso do saldo da carteira x402."
        }
      },
      "retorno": "ConsultaCnpj",
      "erros": {
        "400": "CNPJ inválido, temas_invalidos ou cnia_atual_invalido (nada é cobrado).",
        "401": "Credencial apresentada e recusada: sessão encerrada ou chave de API inválida.",
        "402": "Franquia grátis do dia e saldo esgotados: `error` (`franquia_esgotada` ou `saldo_esgotado`), `message`, `gratis` (com `renova_em`) e `ofertas[]` com a URL de compra, na forma de `GET /api/consulta`. No portal que vende a chamada avulsa, também `accepts` (x402) e `por_chamada` (`preco_usd`, `como`): repita a chamada com a prova x402 ou com `Authorization: Bearer cred_…`, sem conta nem pacote; só se cobra o que a origem entregou.",
        "404": "Não existe na base (a consulta não é cobrada).",
        "429": "Consultas demais neste minuto; respeite o Retry-After (a consulta não é cobrada).",
        "503": "Fonte dos dados ou serviço de saldo fora do ar; cnia_indisponivel quando o CNIA exigido não respondeu. A consulta não é cobrada."
      },
      "exemplo": "curl -s '$ORIGIN/api/consulta/cnpj/00000000000191?lingua=pt'",
      "returns": "{ consulta, temas?, cnpj, empresa, sancoes?{total,vigentes,porCadastro,itens,mais,conferidoEm,cadastros}, cnia?{situacao,registros,conferidoEm,cnpjs,certidoes?,link}, dividaAtiva?{inscricoes,valor,valorCorresponsavel,ajuizadas,maisAntiga,porNatureza,porSituacao,maiores,mais,referencia,conferidoEm,fonte}, parcelamentos?{quantidade,saldo,itens,referencia,conferidoEm,fonte}, regimeTributario?{atual,anos,referencia,conferidoEm,fonte}, beneficiosFiscais?{itens,mais,importacao,referencia,conferidoEm,fonte}, obras?{quantidade,ativas,anteriores,destinacoes,itens,mais,referencia,conferidoEm,fonte}, devedorContumaz?{consta,itens,lista,referencia,conferidoEm,fonte}, ambiental?{autos,embargos}, trabalhoEscravo?{consta,itens,referencia,conferidoEm,fonte}, governo?{quantidade,valor,ultimos12Meses,orgaos,itens,mais,referencia,conferidoEm,fonte}, pagamentos?{valor,quantidade,desde,ultimo,orgaos,referencia,fonte}, notasFederais?{valor,notas,desde,ate,compradores,anos,referencia,fonte}, contratosFederais?{quantidade,valor,desde,orgaos,itens,mais,referencia,fonte}, campanhas?{quantidade,valor,anos,partidos,itens,mais,referencia,fonte}, municipiosSp?{pago,empenhado,municipios,desde,anos,orgaos,elementos,modalidades,referencia,fonte}, pep?{quantidade,pessoas,referencia,conferidoEm,fonte}, registros?{itens,fontes}, bndes?{contratos,ativos,valorContratado,valorDesembolsado,itens,mais,referencia,fonte}, fundos?{proprio,fundos,patrimonio,papeis,itens,mais,referencia,fonte}, ponto?{lat,lon,precisao,logradouro,numero,bairro,cidade,uf,cep,fonte}, uso{via,restantes?,preco_usd?,repetido?,saldo_usd?}, _links }",
      "url": "https://editalmd.com/api/consulta/cnpj/:cnpj",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/consulta/planos/:oferta",
      "auth": "none",
      "grupo": "Consulta de CNPJ, sanções e endereço",
      "summary": "Compra o pacote avulso ou um dos três planos, com crédito ou x402, inclusive sem conta.",
      "desc": "Sem pagamento, retorna 402 com o preço em dólar e reais. O corpo usa x402 v1; PAYMENT-REQUIRED usa v2. Com conta ou crédito, o saldo fica com esse titular. Sem identificação, fica com a carteira confirmada pelo pagamento x402. Para usar esse saldo, assine o desafio da carteira e obtenha a credencial mmw_… nas URLs wallet_start e wallet_token da resposta. O pagamento não concede login nem acesso à conta vinculada. Plano soma 30 dias e a quota; pacote vale 90 dias. Sem renovação automática.",
      "params": {
        "oferta": {
          "desc": "A oferta: `pacote`, `basico`, `profissional` ou `empresa`.",
          "exemplo": "basico"
        }
      },
      "query": {
        "lingua": {
          "tipo": "string",
          "desc": "Língua das mensagens: `pt` ou `en` (padrão: a do navegador, senão inglês).",
          "valores": [
            "pt",
            "en"
          ]
        },
        "compra": {
          "tipo": "string",
          "desc": "Marca desta compra (8 a 64 caracteres `A-Za-z0-9_-`): no crédito, repetir com a mesma marca não cobra de novo. No x402, não assine outro pagamento para repetir a mesma compra."
        }
      },
      "headers": {
        "X-Credito": {
          "tipo": "string",
          "obrigatorio": false,
          "desc": "Token do crédito pré-pago (`cred_…`) que paga a compra."
        },
        "X-Api-Key": {
          "tipo": "string",
          "obrigatorio": false,
          "desc": "Chave de API da conta (`mmk_…`): o plano fica com a conta."
        },
        "X-PAYMENT": {
          "tipo": "string",
          "obrigatorio": false,
          "desc": "Pagamento x402 assinado, a partir da cotação do 402."
        },
        "PAYMENT-SIGNATURE": {
          "tipo": "string",
          "obrigatorio": false,
          "desc": "Pagamento x402 v2. Use apenas um header de pagamento."
        },
        "X-Wallet-Token": {
          "tipo": "string",
          "obrigatorio": false,
          "desc": "Credencial mmw_… deste portal, obtida pela assinatura da carteira em /api/auth/wallet/agent/start e /api/auth/wallet/agent/token. Autoriza o uso do saldo da carteira x402."
        }
      },
      "retorno": "ConsultaCompra",
      "erros": {
        "400": "Pagamento malformado, versão desconhecida ou oferta diferente da cotada.",
        "401": "Credencial apresentada e recusada. Sem credencial, a compra segue pelo x402.",
        "402": "Pagamento necessário: o preço, o crédito e o x402.",
        "404": "Oferta desconhecida.",
        "409": "Cobrança desligada nesta oferta: nada foi cobrado nem criado.",
        "503": "Oferta sem preço configurado ou pagamento fora do ar."
      },
      "exemplo": "curl -s -X POST '$ORIGIN/api/consulta/planos/basico?compra=minha-compra-01' -H \"X-Credito: $CREDITO\"",
      "returns": "{ comprado, nome, consultas, valido_ate, saldo, via, cobranca, recibo, message, _links }",
      "url": "https://editalmd.com/api/consulta/planos/:oferta",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/credito/assinaturas",
      "auth": "session",
      "grupo": "Assinaturas",
      "summary": "Lista até 20 assinaturas da própria conta neste produto.",
      "desc": "Exige venda mensal ativa ou homologação habilitada e pagamento de teste autorizado pelo servidor. Sem essa autorização, responde 404. Filtra conta, produto, recebedor e ambiente. Não consulta o Asaas ou conta a tabela. A oferta aceita permanece disponível quando o catálogo deixa de vender essa oferta. Sandbox exige bilhete válido. A query completa admite até 640 caracteres, incluindo o cursor.",
      "query": {
        "dev": {
          "tipo": "string",
          "desc": "Bilhete de homologação assinado e vigente. Não autoriza outra conta."
        },
        "x402_dev": {
          "tipo": "string",
          "desc": "Mesmo bilhete de `dev`. Use apenas um desses parâmetros por pedido."
        },
        "cursor": {
          "tipo": "string",
          "desc": "proximo recebido na página anterior: data UTC em ISO com milissegundos, ~ e ID hexadecimal de 32 caracteres."
        },
        "recurso": {
          "tipo": "string",
          "desc": "Recurso do produto: até 256 caracteres, sem controles. Filtra a assinatura da própria conta; vazio indica compra por conta."
        }
      },
      "headers": {
        "X-X402-Dev": {
          "tipo": "string",
          "desc": "Bilhete assinado e vigente da homologação. Sem ele, a flag do corpo não autoriza sandbox."
        }
      },
      "colecao": {
        "porPagina": 20,
        "teto": 20,
        "anda": "Use proximo como cursor. Ordem decrescente por criado_em e id. Null encerra a lista."
      },
      "retorno": {
        "itens": {
          "tipo": "RegistroDeAssinatura[]",
          "desc": "Até 20 registros da própria conta."
        },
        "proximo": {
          "tipo": "string",
          "nulo": true,
          "desc": "Cursor da próxima página, ou null."
        },
        "simulado": {
          "tipo": "bool",
          "desc": "Ambiente autorizado pelo servidor para este pedido."
        }
      },
      "erros": {
        "400": "Corpo, query, oferta, aceite, cartão ou ambiente inválido; cartão recusado.",
        "401": "Sessão ausente ou inválida; chave de API não autoriza estes pedidos.",
        "403": "Origem ou cookie inválido; na escrita, proteção CSRF inválida.",
        "404": "Venda e homologação não autorizadas; assinatura inexistente, de outra conta, produto, recebedor ou ambiente.",
        "431": "Cabeçalho de cookies acima de 8 KiB.",
        "503": "Conta, banco, configuração ou provedor indisponível; limite de quatro operações simultâneas atingido."
      },
      "exemplo": "curl -s $ORIGIN/api/credito/assinaturas -b sessao.cookies",
      "returns": "{ itens[{recurso,id,oferta_id,oferta,estado,simulado,pagamento_em,criado_em,atualizado_em,cancelamento_em,cancelado_em}], proximo, simulado }",
      "url": "https://editalmd.com/api/credito/assinaturas",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "GET",
      "path": "/api/credito/assinaturas/ofertas",
      "auth": "none",
      "grupo": "Assinaturas",
      "summary": "Consulta a oferta mensal e o ambiente deste pedido, quando o produto habilita assinaturas.",
      "desc": "Exige venda mensal ativa ou homologação habilitada e pagamento de teste autorizado pelo servidor. Sem essa autorização, responde 404. Não cria cobrança, reserva ou benefício. Não converte o teste em contratação.",
      "query": {
        "dev": {
          "tipo": "string",
          "desc": "Bilhete de homologação assinado e vigente. Opcional; até 512 caracteres na query."
        },
        "x402_dev": {
          "tipo": "string",
          "desc": "Mesmo bilhete de `dev`. Use apenas um desses parâmetros por pedido."
        }
      },
      "headers": {
        "X-X402-Dev": {
          "tipo": "string",
          "desc": "Bilhete assinado e vigente da homologação. Sem ele, a flag do corpo não autoriza sandbox."
        }
      },
      "retorno": {
        "ofertas": {
          "tipo": "OfertaDeAssinatura[]",
          "desc": "De 1 a 8 ofertas versionadas deste produto."
        },
        "simulado": {
          "tipo": "bool",
          "desc": "Ambiente autorizado pelo servidor para este pedido."
        }
      },
      "erros": {
        "400": "Corpo, query, oferta, aceite, cartão ou ambiente inválido; cartão recusado.",
        "404": "Venda e homologação não autorizadas; assinatura inexistente, de outra conta, produto, recebedor ou ambiente.",
        "503": "Conta, banco, configuração ou provedor indisponível; limite de quatro operações simultâneas atingido."
      },
      "exemplo": "curl -s $ORIGIN/api/credito/assinaturas/ofertas",
      "returns": "{ ofertas[{id,produto,versao,preco_centavos,moeda,ciclo,renovacao_automatica,compromisso_meses,compromisso_semanas,cancelamento,acesso_pago,teste_dias,conversao_teste,beneficios,hash}], simulado }",
      "url": "https://editalmd.com/api/credito/assinaturas/ofertas",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "POST",
      "path": "/api/credito/assinaturas",
      "auth": "session",
      "grupo": "Assinaturas",
      "summary": "Contrata e paga a oferta mensal com cartão pela API, quando habilitado.",
      "desc": "Exige venda mensal ativa ou homologação habilitada e pagamento de teste autorizado pelo servidor. Sem essa autorização, responde 404. Exige sessão autenticada há até 2 horas. Não aceita Authorization ou X-Api-Key. Envie somente os campos declarados, com JSON até 4 KiB e HTTPS. recurso só é aceito quando o produto exige e confirma sua titularidade no servidor. simulado deve coincidir com o catálogo e com o ambiente autorizado deste pedido. Se o bilhete vencer, o servidor recusa a troca para produção antes de criar a cobrança. Preço e benefícios vêm do servidor. O cartão passa somente nesta requisição ao Asaas; não é salvo nem devolvido. O IP do comprador vem do servidor, nunca do corpo. Aguarde até 120 segundos. Repetir a oferta retorna a reserva existente. Resultado inconclusivo exige consulta pela referência antes de outra criação. A criação não concede benefício. O pagamento confirmado no Asaas concede o período pago.",
      "query": {
        "dev": {
          "tipo": "string",
          "desc": "Bilhete de homologação assinado e vigente. Opcional; até 512 caracteres na query."
        },
        "x402_dev": {
          "tipo": "string",
          "desc": "Mesmo bilhete de `dev`. Use apenas um desses parâmetros por pedido."
        }
      },
      "headers": {
        "X-X402-Dev": {
          "tipo": "string",
          "desc": "Bilhete assinado e vigente da homologação. Sem ele, a flag do corpo não autoriza sandbox."
        },
        "Origin": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Origem HTTPS exata deste produto."
        },
        "X-CSRF-Token": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Token de 64 caracteres do bootstrap da sessão deste produto. Protege contra pedidos de outro site."
        }
      },
      "corpo": {
        "recurso": {
          "tipo": "string",
          "desc": "Obrigatório somente no produto que vende por recurso. O servidor confirma que a conta é dona dele."
        },
        "simulado": {
          "tipo": "bool",
          "obrigatorio": true,
          "desc": "Valor do catálogo. Declara intenção; não concede autorização de teste."
        },
        "aceite": {
          "tipo": "AceiteDeAssinatura",
          "obrigatorio": true,
          "desc": "Somente oferta_id, versao, hash e renovacao; iguais ao catálogo atual."
        },
        "cartao": {
          "tipo": "CartaoDeAssinatura",
          "obrigatorio": true,
          "desc": "Dados do cartão e de cobrança do titular. Não envie preço, IP, ambiente ou identificador de outra conta."
        }
      },
      "retorno": "RegistroDeAssinatura",
      "erros": {
        "400": "Corpo, query, oferta, aceite, cartão ou ambiente inválido; cartão recusado.",
        "401": "Sessão ausente ou inválida; chave de API não autoriza estes pedidos.",
        "403": "Origem ou cookie inválido; na escrita, proteção CSRF inválida.",
        "404": "Venda e homologação não autorizadas; assinatura inexistente, de outra conta, produto, recebedor ou ambiente.",
        "409": "Estado incompatível ou outra oferta já reservada para esta conta e produto.",
        "413": "Corpo JSON acima de 4 KiB.",
        "415": "Tipo do corpo diferente de application/json, ou corpo comprimido.",
        "429": "A conta atingiu o limite diário de criação de cobranças.",
        "431": "Cabeçalho de cookies acima de 8 KiB.",
        "503": "Conta, banco, configuração ou provedor indisponível; limite de quatro operações simultâneas atingido."
      },
      "exemplo": "curl -s -X POST $ORIGIN/api/credito/assinaturas -b sessao.cookies -H \"Origin: $ORIGIN\" -H \"X-CSRF-Token: $CSRF\" -H \"content-type: application/json\" --data-binary @contratacao.json",
      "returns": "{ recurso, id, oferta_id, oferta{id,produto,versao,preco_centavos,moeda,ciclo,renovacao_automatica,compromisso_meses,compromisso_semanas,cancelamento,acesso_pago,teste_dias,conversao_teste,beneficios,hash}, estado, simulado, pagamento_em, criado_em, atualizado_em, cancelamento_em, cancelado_em }",
      "url": "https://editalmd.com/api/credito/assinaturas",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "GET",
      "path": "/api/credito/assinaturas/:id",
      "auth": "session",
      "grupo": "Assinaturas",
      "summary": "Consulta a própria assinatura e a oferta aceita, sem criar pagamento.",
      "desc": "Exige venda mensal ativa ou homologação habilitada e pagamento de teste autorizado pelo servidor. Sem essa autorização, responde 404. Exige sessão válida deste produto. Não consulta o provedor. Sandbox exige bilhete válido também na leitura.",
      "query": {
        "dev": {
          "tipo": "string",
          "desc": "Bilhete de homologação assinado e vigente. Opcional; até 512 caracteres na query."
        },
        "x402_dev": {
          "tipo": "string",
          "desc": "Mesmo bilhete de `dev`. Use apenas um desses parâmetros por pedido."
        },
        "recurso": {
          "tipo": "string",
          "desc": "Recurso do produto: até 256 caracteres, sem controles. Filtra a assinatura da própria conta; vazio indica compra por conta."
        }
      },
      "headers": {
        "X-X402-Dev": {
          "tipo": "string",
          "desc": "Bilhete assinado e vigente da homologação. Sem ele, a flag do corpo não autoriza sandbox."
        }
      },
      "params": {
        "id": {
          "tipo": "string",
          "desc": "ID local da assinatura: 32 caracteres hexadecimais minúsculos.",
          "exemplo": "0123456789abcdef0123456789abcdef"
        }
      },
      "retorno": "RegistroDeAssinatura",
      "erros": {
        "400": "Corpo, query, oferta, aceite, cartão ou ambiente inválido; cartão recusado.",
        "401": "Sessão ausente ou inválida; chave de API não autoriza estes pedidos.",
        "403": "Origem ou cookie inválido; na escrita, proteção CSRF inválida.",
        "404": "Venda e homologação não autorizadas; assinatura inexistente, de outra conta, produto, recebedor ou ambiente.",
        "431": "Cabeçalho de cookies acima de 8 KiB.",
        "503": "Conta, banco, configuração ou provedor indisponível; limite de quatro operações simultâneas atingido."
      },
      "exemplo": "curl -s $ORIGIN/api/credito/assinaturas/0123456789abcdef0123456789abcdef -b sessao.cookies",
      "returns": "{ recurso, id, oferta_id, oferta{id,produto,versao,preco_centavos,moeda,ciclo,renovacao_automatica,compromisso_meses,compromisso_semanas,cancelamento,acesso_pago,teste_dias,conversao_teste,beneficios,hash}, estado, simulado, pagamento_em, criado_em, atualizado_em, cancelamento_em, cancelado_em }",
      "url": "https://editalmd.com/api/credito/assinaturas/:id",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "POST",
      "path": "/api/credito/assinaturas/:id",
      "auth": "session",
      "grupo": "Assinaturas",
      "summary": "Interrompe futuras cobranças da própria assinatura e mantém o período pago.",
      "desc": "Exige venda mensal ativa ou homologação habilitada e pagamento de teste autorizado pelo servidor. Sem essa autorização, responde 404. Envie somente {} com JSON até 4 KiB, sessão válida, origem e CSRF. Grava o pedido antes de chamar o Asaas. Cancelamento pendente não equivale a cancelamento confirmado. Pode repetir o mesmo pedido. Reembolso tem tratamento próprio; este pedido não estorna o pagamento.",
      "query": {
        "dev": {
          "tipo": "string",
          "desc": "Bilhete de homologação assinado e vigente. Opcional; até 512 caracteres na query."
        },
        "x402_dev": {
          "tipo": "string",
          "desc": "Mesmo bilhete de `dev`. Use apenas um desses parâmetros por pedido."
        },
        "recurso": {
          "tipo": "string",
          "desc": "Recurso do produto: até 256 caracteres, sem controles. Filtra a assinatura da própria conta; vazio indica compra por conta."
        }
      },
      "headers": {
        "X-X402-Dev": {
          "tipo": "string",
          "desc": "Bilhete assinado e vigente da homologação. Sem ele, a flag do corpo não autoriza sandbox."
        },
        "Origin": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Origem HTTPS exata deste produto."
        },
        "X-CSRF-Token": {
          "tipo": "string",
          "obrigatorio": true,
          "desc": "Token de 64 caracteres do bootstrap da sessão deste produto. Protege contra pedidos de outro site."
        }
      },
      "params": {
        "id": {
          "tipo": "string",
          "desc": "ID local da assinatura: 32 caracteres hexadecimais minúsculos.",
          "exemplo": "0123456789abcdef0123456789abcdef"
        }
      },
      "body": {},
      "retorno": "RegistroDeAssinatura",
      "erros": {
        "400": "Corpo, query, oferta, aceite, cartão ou ambiente inválido; cartão recusado.",
        "401": "Sessão ausente ou inválida; chave de API não autoriza estes pedidos.",
        "403": "Origem ou cookie inválido; na escrita, proteção CSRF inválida.",
        "404": "Venda e homologação não autorizadas; assinatura inexistente, de outra conta, produto, recebedor ou ambiente.",
        "409": "Estado incompatível ou outra oferta já reservada para esta conta e produto.",
        "413": "Corpo JSON acima de 4 KiB.",
        "415": "Tipo do corpo diferente de application/json, ou corpo comprimido.",
        "431": "Cabeçalho de cookies acima de 8 KiB.",
        "503": "Conta, banco, configuração ou provedor indisponível; limite de quatro operações simultâneas atingido."
      },
      "exemplo": "curl -s -X POST $ORIGIN/api/credito/assinaturas/0123456789abcdef0123456789abcdef -b sessao.cookies -H \"Origin: $ORIGIN\" -H \"X-CSRF-Token: $CSRF\" -H \"content-type: application/json\" -d '{}'",
      "returns": "{ recurso, id, oferta_id, oferta{id,produto,versao,preco_centavos,moeda,ciclo,renovacao_automatica,compromisso_meses,compromisso_semanas,cancelamento,acesso_pago,teste_dias,conversao_teste,beneficios,hash}, estado, simulado, pagamento_em, criado_em, atualizado_em, cancelamento_em, cancelado_em }",
      "url": "https://editalmd.com/api/credito/assinaturas/:id",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "GET",
      "path": "/api/credito/assinaturas/:id/estado",
      "auth": "session",
      "stream": true,
      "grupo": "Assinaturas",
      "summary": "Acompanha mudanças na própria assinatura pelo canal de tempo real.",
      "desc": "Exige venda mensal ativa ou homologação habilitada e pagamento de teste autorizado pelo servidor. Sem essa autorização, responde 404. Exige sessão humana deste produto. Devolve somente ID e cursor, inclusive após reconexão. O sinal não concede acesso pago nem expõe dados financeiros. Ao mudar, consulte o registro autenticado da assinatura. A leitura do registro mantém as verificações de ambiente, recebedor e recurso.",
      "query": {
        "dev": {
          "tipo": "string",
          "desc": "Bilhete de homologação assinado e vigente. Opcional; até 512 caracteres na query."
        },
        "x402_dev": {
          "tipo": "string",
          "desc": "Mesmo bilhete de `dev`. Use apenas um desses parâmetros por pedido."
        }
      },
      "headers": {
        "X-X402-Dev": {
          "tipo": "string",
          "desc": "Bilhete assinado e vigente da homologação. Sem ele, a flag do corpo não autoriza sandbox."
        }
      },
      "params": {
        "id": {
          "tipo": "string",
          "desc": "ID local da assinatura: 32 caracteres hexadecimais minúsculos.",
          "exemplo": "0123456789abcdef0123456789abcdef"
        }
      },
      "retorno": {
        "id": {
          "tipo": "string",
          "desc": "ID local da assinatura: 32 caracteres hexadecimais minúsculos.",
          "exemplo": "0123456789abcdef0123456789abcdef"
        },
        "cursor": {
          "tipo": "string",
          "desc": "Versão do estado. Compare por igualdade; não interprete como confirmação de pagamento."
        }
      },
      "erros": {
        "400": "Corpo, query, oferta, aceite, cartão ou ambiente inválido; cartão recusado.",
        "401": "Sessão ausente ou inválida; chave de API não autoriza estes pedidos.",
        "403": "Origem ou cookie inválido; na escrita, proteção CSRF inválida.",
        "404": "Venda e homologação não autorizadas; assinatura inexistente, de outra conta, produto, recebedor ou ambiente.",
        "431": "Cabeçalho de cookies acima de 8 KiB.",
        "503": "Conta, banco, configuração ou provedor indisponível; limite de quatro operações simultâneas atingido."
      },
      "exemplo": "curl -s $ORIGIN/api/credito/assinaturas/0123456789abcdef0123456789abcdef/estado -b sessao.cookies",
      "returns": "{ id, cursor }",
      "url": "https://editalmd.com/api/credito/assinaturas/:id/estado",
      "auth_detail": "Conta: cookie HttpOnly `__Host-mm-session-editalmd-web`, gravado por `/api/auth/callback` depois de entrar em `/conta/global`; escrita exige a mesma origem e `X-CSRF-Token` de `/api/auth/bootstrap`. Não há bearer para pessoas. Conta não concede documentos sem compra vinculada."
    },
    {
      "method": "GET",
      "path": "/api/pricing",
      "auth": "none",
      "grupo": "Descoberta",
      "summary": "Preços vigentes e franquias gratuitas.",
      "retorno": {
        "product": {
          "tipo": "string",
          "desc": "Product name."
        },
        "quota": {
          "tipo": "PaymentQuota",
          "desc": "Public allowances and current list prices; not personal usage."
        },
        "pricing": {
          "tipo": "string",
          "desc": "Absolute URL of the current price list."
        },
        "billing": {
          "tipo": "string",
          "desc": "Absolute URL of payment discovery or the existing billing summary."
        },
        "api_index": {
          "tipo": "string",
          "desc": "Absolute URL of the API catalog."
        }
      },
      "erros": {
        "405": "Use GET ou HEAD."
      },
      "exemplo": "curl -s $ORIGIN/api/pricing",
      "returns": "{ product, quota{free,paid,how_to_pay,live,free_now?,charged_now?,trial?}, pricing, billing, api_index }",
      "url": "https://editalmd.com/api/pricing",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    },
    {
      "method": "GET",
      "path": "/api/billing",
      "auth": "none",
      "grupo": "Descoberta",
      "summary": "Descoberta pública de pagamento e crédito pré-pago.",
      "retorno": {
        "product": {
          "tipo": "string",
          "desc": "Product name."
        },
        "quota": {
          "tipo": "PaymentQuota",
          "desc": "Public allowances and current list prices; not personal usage."
        },
        "pricing": {
          "tipo": "string",
          "desc": "Absolute URL of the current price list."
        },
        "billing": {
          "tipo": "string",
          "desc": "Absolute URL of payment discovery or the existing billing summary."
        },
        "api_index": {
          "tipo": "string",
          "desc": "Absolute URL of the API catalog."
        },
        "payment": {
          "tipo": "PaymentX402",
          "desc": "Public x402 configuration; pay_to=null means not configured."
        },
        "credit": {
          "tipo": "PaymentCredit",
          "desc": "Prepaid credit entry point. Never contains a balance or token."
        }
      },
      "erros": {
        "405": "Use GET ou HEAD."
      },
      "exemplo": "curl -s $ORIGIN/api/billing",
      "returns": "{ product, quota{free,paid,how_to_pay,live,free_now?,charged_now?,trial?}, pricing, billing, api_index, payment{provider,mode,network,chain_id,pay_to,homolog,dev,dev_gate,alternavel,gratis?,cobrados?,facilitator,asset,asset_address,faucet,wallets}, credit{url,header} }",
      "url": "https://editalmd.com/api/billing",
      "auth_detail": "Público. Agente não se cadastra: quando a rota cobra, cobra por requisição (x402) ou desconta de crédito pré-pago."
    }
  ],
  "mcp_tools": [
    "evaluation_quota",
    "evaluation_premium",
    "evaluation_basic",
    "evaluation_basic_result",
    "company_documents",
    "attach_company_document",
    "remove_company_document",
    "analyze_participation",
    "get_participation",
    "list_my_companies",
    "search_companies",
    "add_company",
    "select_company",
    "remove_company",
    "awarded_prices",
    "framework_agreements",
    "procurement_plans",
    "tenders_outside_pncp",
    "my_account",
    "my_documents",
    "my_procurements",
    "documento_vincular",
    "documento_acesso",
    "account_tracking",
    "claim_guest_tracking",
    "lookup_reference",
    "preview_alert",
    "update_alert",
    "list_saved",
    "save_procurement",
    "remove_saved",
    "gerar_markdown",
    "generation_status",
    "original_status",
    "request_original",
    "criar_cobranca",
    "estado_cobranca",
    "list_examples",
    "get_document",
    "get_document_dossier",
    "list_document_files",
    "api_index",
    "health",
    "search_tenders",
    "get_deadlines",
    "get_procurement",
    "who_supplies",
    "open_tenders_in_field",
    "get_tender_markdown",
    "get_qualification",
    "get_reading_manifest",
    "create_owner",
    "get_owner",
    "rotate_webhook_secret",
    "create_alert",
    "create_alerts_by_cnpj",
    "list_cnaes",
    "list_alert_matches",
    "watch_procurement",
    "list_watch_events",
    "credito_saldo",
    "credito_recarregar",
    "recibo",
    "consulta_cadastro",
    "consulta_endereco",
    "consulta_sugerir",
    "consulta_cnpj",
    "consulta_cep",
    "consulta_planos",
    "consulta_comprar",
    "api_access",
    "api_access_buy",
    "list_plans",
    "buy_plan",
    "cancel_plan",
    "pricing",
    "billing",
    "get_api_x402_precos"
  ],
  "cota": {
    "free": [
      {
        "o_que": "análise adicional e integração medida (`GET /api/consulta/cnpj/:cnpj`); a pesquisa, a ficha básica em `/cadastro/:cnpj` e o CEP em `/endereco/:cep` são grátis e não consomem esta franquia",
        "limite": "10 por dia, por conta (sem conta, por rede), somadas nos portais; depois, o saldo do plano ou do pacote (válido em todos os portais)",
        "janela": null
      },
      {
        "o_que": "piloto documental individual",
        "limite": "1 premium e 100 básicos até 50 páginas; X-Agent-Pass; validade/capacidade em /api/avaliacao",
        "janela": null
      },
      {
        "o_que": "busca e ficha da compra",
        "limite": "sem cota",
        "janela": null
      },
      {
        "o_que": "exemplos e consulta de estado/cotação",
        "limite": "sem cota",
        "janela": null
      },
      {
        "o_que": "licitações salvas e prévia de interesses",
        "limite": "200 salvas por dono; prévia de até 20 compras em 7 dias",
        "janela": null
      }
    ],
    "paid": [
      {
        "o_que": "consulta de CNPJ e endereço, Pacote avulso: 200 consultas por 90 dias, sem renovação automática (`POST /api/consulta/planos/pacote`)",
        "price_usd": 0.91
      },
      {
        "o_que": "consulta de CNPJ e endereço, Básico: 1000 consultas por 30 dias, sem renovação automática (`POST /api/consulta/planos/basico`)",
        "price_usd": 3.62
      },
      {
        "o_que": "consulta de CNPJ e endereço, Profissional: 5000 consultas por 30 dias, sem renovação automática (`POST /api/consulta/planos/profissional`)",
        "price_usd": 10.9
      },
      {
        "o_que": "consulta de CNPJ e endereço, Empresa: 20000 consultas por 30 dias, sem renovação automática (`POST /api/consulta/planos/empresa`)",
        "price_usd": 36.35
      },
      {
        "o_que": "1,000 basic reads across /empresas, /enderecos and /licitacoes, valid for 30 days; availability and purchase: GET/POST /api/acesso; no automatic renewal",
        "price_usd": 1
      },
      {
        "o_que": "acesso individual ao documento, por página; inclui geração necessária",
        "price_usd": 0.02
      },
      {
        "o_que": "habilitação e dossiê incluídos no acesso ao documento",
        "price_usd": 0
      },
      {
        "o_que": "alerta além do 1º (30 dias)",
        "price_usd": 0.1
      },
      {
        "o_que": "vigia além da 1ª",
        "price_usd": 0.05
      },
      {
        "o_que": "Preço que ganha completo, por consulta: quem vence, quem compra, por estado, por mês e os itens (o resumo é grátis)",
        "price": "R$ 2,75"
      },
      {
        "o_que": "Análise assistida de uma licitação: exigências conferidas com a sua empresa, até 50 páginas",
        "price": "R$ 149,00"
      },
      {
        "o_que": "Pesquisa de preços em relatório no formato da IN 65/2021, até 5 itens",
        "price": "R$ 199,00"
      },
      {
        "o_que": "Plano Básico de análise: 1.000 unidades por mês no cartão, com renovação automática, ou por 30 dias no Pix, USDC ou saldo",
        "price": "R$ 97,00"
      },
      {
        "o_que": "Plano Profissional de análise: 10.000 unidades por mês no cartão, com renovação automática, ou por 30 dias no Pix, USDC ou saldo",
        "price": "R$ 797,00"
      },
      {
        "o_que": "Plano Empresarial de análise: 100.000 unidades por mês no cartão, com renovação automática, ou por 30 dias no Pix, USDC ou saldo",
        "price": "R$ 5.997,00"
      },
      {
        "o_que": "GET /api/x402/precos — O preço que ganha resumido para o agente, pago por chamada, sem conta: o resumo completo e até 10 itens.",
        "price_usd": 0.1
      }
    ],
    "how_to_pay": "Cada comprador paga $0.02 por página pelo próprio acesso, inclusive ao texto pronto, via x402/crédito ou depósito USDC. Geração necessária incluída. Exemplos livres; piloto individual oferece um premium e 100 básicos até 50 páginas com X-Agent-Pass (/api/avaliacao, guia /avaliacao.md), sujeito a validade, capacidade e orçamento. Básico não revisado; premium não equivale a aprovação de fidelidade. Conta opcional em /conta/global; /api/me/documentos e /compras são privados. Compra autenticada vincula automaticamente; a anônima pode ser vinculada em POST /api/documento/:id/vincular com sessão e X-Editalmd-Acesso. Depois do vínculo só a conta abre. Sem vínculo, guarde acesso.codigo. GET nunca inicia geração.",
    "live": "https://editalmd.com/api/"
  }
}