{
  "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. Cinco 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": "232bdf32",
  "base_url": "https://staging.editalmd.com",
  "docs": {
    "llms": "https://staging.editalmd.com/llms.txt",
    "llms_full": "https://staging.editalmd.com/llms-full.txt",
    "openapi": "https://staging.editalmd.com/openapi.json",
    "mcp": "https://staging.editalmd.com/mcp",
    "pricing": "https://staging.editalmd.com/api/pricing",
    "billing": "https://staging.editalmd.com/api/billing",
    "human_ui": "https://staging.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.",
        "hierarchy": "UF → município → bairro/localidade → rua → endereços",
        "url": "https://api.pontofato.com/enderecos/",
        "formats": {
          "html": "https://api.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.",
        "hierarchy": "Modalidade → UF → ano → mês → dia → município → compras",
        "url": "https://api.editalmd.com/licitacoes/",
        "formats": {
          "html": "https://api.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. Cinco 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 header `X-Credito`). Não é conta: é portador de saldo.",
    "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. Cinco exemplos são livres.",
    "owner": "Convidado edm_… em Authorization: Bearer (POST /api/dono, sem cadastro; só o hash fica guardado) ou a sessão da conta, que é dona direto das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. 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. Cinco 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://staging.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/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://staging.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://staging.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://staging.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://staging.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": "session",
      "grupo": "Análise de participação",
      "params": {
        "cnpj": {
          "desc": "CNPJ de 14 dígitos vinculado à conta.",
          "exemplo": "00394460000141"
        }
      },
      "erros": {
        "400": "Entrada inválida.",
        "401": "Sessão necessária.",
        "402": "Acesso ao edital necessário.",
        "403": "Origem recusada.",
        "404": "Empresa ou documento ausente na conta.",
        "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 'Authorization: Bearer $SESS'",
      "retorno": "DocumentosEmpresa",
      "returns": "{ itens[{id,nome,tipo,bytes,paginas,enviado_em}], revisao, limite, limite_bytes, limite_paginas }",
      "url": "https://staging.editalmd.com/api/me/empresas/:cnpj/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": "POST",
      "path": "/api/me/empresas/:cnpj/documentos",
      "summary": "Adiciona PDF de atestado, certidão ou outro comprovante à empresa.",
      "auth": "session",
      "grupo": "Análise de participação",
      "params": {
        "cnpj": {
          "desc": "CNPJ de 14 dígitos vinculado à conta.",
          "exemplo": "00394460000141"
        }
      },
      "erros": {
        "400": "Entrada inválida.",
        "401": "Sessão necessária.",
        "402": "Acesso ao edital necessário.",
        "403": "Origem recusada.",
        "404": "Empresa ou documento ausente na conta.",
        "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://staging.editalmd.com/api/me/empresas/:cnpj/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/empresas/:cnpj/documentos/:arquivo",
      "summary": "Baixa o PDF privado, sem chamada de IA.",
      "auth": "session",
      "grupo": "Análise de participação",
      "params": {
        "cnpj": {
          "desc": "CNPJ de 14 dígitos vinculado à conta.",
          "exemplo": "00394460000141"
        },
        "arquivo": {
          "desc": "SHA-256 retornado no envio.",
          "exemplo": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
        }
      },
      "erros": {
        "400": "Entrada inválida.",
        "401": "Sessão necessária.",
        "402": "Acesso ao edital necessário.",
        "403": "Origem recusada.",
        "404": "Empresa ou documento ausente na conta.",
        "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 'Authorization: Bearer $SESS'",
      "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://staging.editalmd.com/api/me/empresas/:cnpj/documentos/:arquivo",
      "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": "DELETE",
      "path": "/api/me/empresas/:cnpj/documentos/:arquivo",
      "summary": "Remove o anexo desta empresa e invalida a análise que o utilizou.",
      "auth": "session",
      "grupo": "Análise de participação",
      "params": {
        "cnpj": {
          "desc": "CNPJ de 14 dígitos vinculado à conta.",
          "exemplo": "00394460000141"
        },
        "arquivo": {
          "desc": "SHA-256 do anexo.",
          "exemplo": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
        }
      },
      "erros": {
        "400": "Entrada inválida.",
        "401": "Sessão necessária.",
        "402": "Acesso ao edital necessário.",
        "403": "Origem recusada.",
        "404": "Empresa ou documento ausente na conta.",
        "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 'Authorization: Bearer $SESS'",
      "retorno": "DocumentosEmpresa",
      "returns": "{ itens[{id,nome,tipo,bytes,paginas,enviado_em}], revisao, limite, limite_bytes, limite_paginas }",
      "url": "https://staging.editalmd.com/api/me/empresas/:cnpj/documentos/:arquivo",
      "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/me/empresas/:cnpj/analises/:id",
      "summary": "Inicia ou retoma comparação de requisitos, atestados e obrigações com a empresa.",
      "auth": "session",
      "grupo": "Análise de participação",
      "params": {
        "cnpj": {
          "desc": "CNPJ de 14 dígitos vinculado à conta.",
          "exemplo": "00394460000141"
        },
        "id": {
          "desc": "ID do documento com dossiê pronto e acesso autorizado.",
          "exemplo": 1993401
        }
      },
      "erros": {
        "400": "Entrada inválida.",
        "401": "Sessão necessária.",
        "402": "Acesso ao edital necessário.",
        "403": "Origem recusada.",
        "404": "Empresa ou documento ausente na conta.",
        "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 desta conta. 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://staging.editalmd.com/api/me/empresas/:cnpj/analises/: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/me/empresas/:cnpj/analises/:id",
      "summary": "Consulta andamento ou resultados paginados; não inicia IA nem modifica a análise.",
      "auth": "session",
      "grupo": "Análise de participação",
      "params": {
        "cnpj": {
          "desc": "CNPJ de 14 dígitos vinculado à conta.",
          "exemplo": "00394460000141"
        },
        "id": {
          "desc": "ID do documento.",
          "exemplo": 1993401
        }
      },
      "erros": {
        "400": "Entrada inválida.",
        "401": "Sessão necessária.",
        "402": "Acesso ao edital necessário.",
        "403": "Origem recusada.",
        "404": "Empresa ou documento ausente na conta.",
        "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://staging.editalmd.com/api/me/empresas/:cnpj/analises/: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/me/empresas",
      "summary": "Lista as empresas importadas e a seleção privada da conta; GET não grava.",
      "auth": "session",
      "grupo": "Empresas",
      "retorno": "EmpresasConta",
      "erros": {
        "400": "CNPJ ou busca inválida.",
        "401": "Sessão necessária.",
        "403": "Origem recusada.",
        "404": "Empresa ausente nesta conta ou na base.",
        "405": "Método não permitido.",
        "409": "Limite de 20 empresas.",
        "503": "Origem, conta ou orçamento indisponível."
      },
      "exemplo": "curl -s -X GET '$ORIGIN/api/me/empresas' -H 'Authorization: Bearer $SESS'",
      "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}], selecionada, limite }",
      "url": "https://staging.editalmd.com/api/me/empresas",
      "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/empresas/busca",
      "summary": "Busca até oito sugestões por razão social ou CNPJ completo; não cadastra.",
      "auth": "session",
      "grupo": "Empresas",
      "retorno": {
        "itens": {
          "tipo": "SugestaoEmpresa[]",
          "desc": "Até oito resultados; refine a busca quando necessário."
        }
      },
      "erros": {
        "400": "CNPJ ou busca inválida.",
        "401": "Sessão necessária.",
        "403": "Origem recusada.",
        "404": "Empresa ausente nesta conta ou na base.",
        "405": "Método não permitido.",
        "409": "Limite de 20 empresas.",
        "503": "Origem, conta ou orçamento indisponível."
      },
      "exemplo": "curl -s '$ORIGIN/api/me/empresas/busca?q=padaria' -H 'Authorization: Bearer $SESS'",
      "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://staging.editalmd.com/api/me/empresas/busca",
      "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/me/empresas/:cnpj",
      "summary": "Importa os dados cadastrais e vincula o CNPJ à conta.",
      "auth": "session",
      "grupo": "Empresas",
      "retorno": "EmpresasConta",
      "erros": {
        "400": "CNPJ ou busca inválida.",
        "401": "Sessão necessária.",
        "403": "Origem recusada.",
        "404": "Empresa ausente nesta conta ou na base.",
        "405": "Método não permitido.",
        "409": "Limite de 20 empresas.",
        "503": "Origem, conta ou orçamento indisponível."
      },
      "exemplo": "curl -s -X PUT '$ORIGIN/api/me/empresas/00394460000141' -H 'Authorization: Bearer $SESS'",
      "params": {
        "cnpj": {
          "desc": "CNPJ completo, 14 dígitos com verificação válida.",
          "exemplo": "00394460000141"
        }
      },
      "desc": "201 ao criar, 200 na repetição sem nova consulta/escrita. Até 20 empresas. Importa os dados cadastrais disponíveis, 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}], selecionada, limite }",
      "url": "https://staging.editalmd.com/api/me/empresas/:cnpj",
      "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/me/empresas/:cnpj/selecionar",
      "summary": "Seleciona uma empresa já cadastrada para trabalhar no edital.",
      "auth": "session",
      "grupo": "Empresas",
      "retorno": "EmpresasConta",
      "erros": {
        "400": "CNPJ ou busca inválida.",
        "401": "Sessão necessária.",
        "403": "Origem recusada.",
        "404": "Empresa ausente nesta conta ou na base.",
        "405": "Método não permitido.",
        "409": "Limite de 20 empresas.",
        "503": "Origem, conta ou orçamento indisponível."
      },
      "exemplo": "curl -s -X PUT '$ORIGIN/api/me/empresas/00394460000141/selecionar' -H 'Authorization: Bearer $SESS'",
      "params": {
        "cnpj": {
          "desc": "CNPJ completo, 14 dígitos com verificação válida.",
          "exemplo": "00394460000141"
        }
      },
      "desc": "Seleção persistida na conta e recuperável em outros aparelhos. Não executa análise; repetir a seleção 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}], selecionada, limite }",
      "url": "https://staging.editalmd.com/api/me/empresas/:cnpj/selecionar",
      "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": "DELETE",
      "path": "/api/me/empresas/:cnpj",
      "summary": "Remove somente o vínculo da própria conta e limpa a seleção se necessário.",
      "auth": "session",
      "grupo": "Empresas",
      "retorno": "EmpresasConta",
      "erros": {
        "400": "CNPJ ou busca inválida.",
        "401": "Sessão necessária.",
        "403": "Origem recusada.",
        "404": "Empresa ausente nesta conta ou na base.",
        "405": "Método não permitido.",
        "409": "Limite de 20 empresas.",
        "503": "Origem, conta ou orçamento indisponível."
      },
      "exemplo": "curl -s -X DELETE '$ORIGIN/api/me/empresas/00394460000141' -H 'Authorization: Bearer $SESS'",
      "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}], selecionada, limite }",
      "url": "https://staging.editalmd.com/api/me/empresas/:cnpj",
      "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/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://staging.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://staging.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://staging.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://staging.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": "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://staging.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 nos últimos 5 minutos; 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://staging.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://staging.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": "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://staging.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://staging.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 ou simulado), 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://staging.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 ou simulado), 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://staging.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://staging.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://staging.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. Cinco 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://staging.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://staging.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://staging.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://staging.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; cinco 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://staging.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. Cinco 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://staging.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://staging.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://staging.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; cinco 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://staging.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. Cinco 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://staging.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://staging.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.",
          "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.",
          "valores": [
            "1"
          ]
        },
        "limite": {
          "tipo": "int",
          "desc": "1 a 50 (padrão 20)."
        }
      },
      "retorno": "Busca",
      "erros": {
        "400": "Termo com menos de 3 letras.",
        "502": "Origem indisponível.",
        "503": "Busca demorada (combinação rara de filtro e offset acima do teto da origem): `busca_demorada`, com `Retry-After` — refine o termo ou reduza o offset."
      },
      "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}], preco_markdown_usd, gratis_acima_de_dias, pago }",
      "url": "https://staging.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://staging.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; prazos e preços 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}, documentos[{id,titulo,tipo,sequencial,publicado_em,caracteres,paginas,motor,formato,sha256,extraido_em,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} }",
      "url": "https://staging.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/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://staging.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. Cinco 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; cinco 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://staging.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. Cinco 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; cinco 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://staging.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. Cinco 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://staging.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, 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://staging.editalmd.com/api/dono",
      "auth_detail": "Convidado edm_… em Authorization: Bearer (POST /api/dono, sem cadastro; só o hash fica guardado) ou a sessão da conta, que é dona direto das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. 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, 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://staging.editalmd.com/api/dono/segredo",
      "auth_detail": "Convidado edm_… em Authorization: Bearer (POST /api/dono, sem cadastro; só o hash fica guardado) ou a sessão da conta, que é dona direto das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. 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. Nulo quando não é possível cotar.",
          "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; 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://staging.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. Nulo quando não é possível cotar.",
          "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://staging.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 cinco 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://staging.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": "/api/exemplos",
      "auth": "none",
      "grupo": "Acervo",
      "summary": "Cinco 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://staging.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://staging.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://staging.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://staging.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; cinco 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."
        }
      },
      "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://staging.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. Cinco 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://staging.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 com documentos em modo de leitura: Markdown paginado, original e arquivos.",
      "query": {
        "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 navegável. O leitor usa /api/compra/:id e a família /api/documento/:id; agentes devem consumir essas APIs diretamente."
      },
      "erros": {
        "404": "Compra não encontrada."
      },
      "exemplo": "curl -fsS $ORIGIN/licitacoes/compra/1996190/",
      "returns": "HTML navegável. O leitor usa /api/compra/:id e a família /api/documento/:id; agentes devem consumir essas APIs diretamente.",
      "url": "https://staging.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": "acesso",
      "grupo": "Acervo",
      "params": {
        "id": {
          "desc": "Identificador do documento na ficha da compra.",
          "exemplo": "9558909"
        }
      },
      "summary": "Baixar o original preservado, com o acesso comprado.",
      "desc": "Entrega o arquivo disponível no acervo, sem iniciar nova extração.",
      "retorno": {
        "_texto": "Binário original (PDF, ZIP ou outro formato), até 96 MiB, com MIME e nome do arquivo."
      },
      "erros": {
        "402": "Sem acesso comprado ou patrocinado válido. Use avaliação individual, compre via POST /api/documento/:id/geracao ou depósito; cinco 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/original -o original",
      "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 original (PDF, ZIP ou outro formato), até 96 MiB, com MIME e nome do arquivo.",
      "url": "https://staging.editalmd.com/api/documento/:id/original",
      "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. Cinco exemplos são livres."
    },
    {
      "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; cinco 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://staging.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. Cinco 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; cinco 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://staging.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. Cinco 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; cinco 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://staging.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. Cinco 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; cinco 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://staging.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. Cinco 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; cinco 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://staging.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. Cinco exemplos são livres."
    },
    {
      "method": "GET",
      "path": "/api/precos",
      "auth": "none",
      "summary": "O preço que ganha para um item parecido: mediana, quartis, desconto sobre a referência, quem vence e quem compra. Grátis.",
      "grupo": "Acervo",
      "desc": "Consulte resultados homologados por descrição do item. Além da amostra (`itens`), a resposta traz `resumo` (n, mediana, p25/p75, menor, maior, 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 ganhos e valor, com porte) e `compradores` (top 10 órgãos, com a última compra) — calculados sobre todos os candidatos do período, não só sobre a amostra. `amostra` diz o critério (até 2.000 itens mais parecidos pelo texto) e se bateu no teto. Unidade de medida é a publicada, sem normalização: compare `unidade` antes de comparar preço. Valores sem saneamento — a exclusão de inexequíveis/excessivos é decisão de quem pesquisa. Pessoa física vencedora sai sem CPF. 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
        }
      },
      "retorno": "Precos",
      "erros": {
        "400": "Termo com menos de 3 letras, UF, meses, limite ou catmat 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,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,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}, itens[{compra_id,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 }",
      "url": "https://staging.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": "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."
        },
        "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, municípios, exclusões, valores e propostas abertas. 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}], aviso, periodo_dias?, limite? }",
      "url": "https://staging.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://staging.editalmd.com/api/salvas",
      "auth_detail": "Convidado edm_… em Authorization: Bearer (POST /api/dono, sem cadastro; só o hash fica guardado) ou a sessão da conta, que é dona direto das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. 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://staging.editalmd.com/api/salvas/:id",
      "auth_detail": "Convidado edm_… em Authorization: Bearer (POST /api/dono, sem cadastro; só o hash fica guardado) ou a sessão da conta, que é dona direto das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. 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://staging.editalmd.com/api/salvas/:id",
      "auth_detail": "Convidado edm_… em Authorization: Bearer (POST /api/dono, sem cadastro; só o hash fica guardado) ou a sessão da conta, que é dona direto das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. 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://staging.editalmd.com/api/salvas/:id",
      "auth_detail": "Convidado edm_… em Authorization: Bearer (POST /api/dono, sem cadastro; só o hash fica guardado) ou a sessão da conta, que é dona direto das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. 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": "Dois modos. Por `termos`: espaço exige todas as palavras, `|` aceita qualquer uma do grupo (`uniforme|fardamento escolar`). Por `cnpj`: o cadastro da empresa informa as atividades (CNAE), o dicionário (`GET /api/cnaes`) transforma cada CNAE numa família de termos e sai um alerta por família distinta, principal primeiro, até `max_familias`; CNAE fora do dicionário não vira alerta e é listado em `empresa.cnaes` com `familia: null`. O primeiro alerta ativo é grátis (`FRANQUIA_ALERTAS`); os seguintes custam `PRECO_ALERTA` por 30 dias cada — no modo CNPJ, numa cobrança só (N × preço), por x402 ou crédito. O cron confere a cada 30 minutos. Canal e-mail exige a sessão da conta — o aviso vai para o e-mail verificado dela, sem código de confirmação — e só existe com `EMAIL_ALERTAS=1`.",
      "corpo": {
        "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, municípios, exclusões, valores e propostas abertas. PATCH substitui o recorte inteiro; {} limpa."
        },
        "canal": {
          "tipo": "string",
          "desc": "`pull` (só a API), `webhook` (POST na sua URL https) 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": {
        "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, 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,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url}, alertas?[{id,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url}], empresa?{cnpj,cnpj_formatado,razao_social,nome_fantasia,situacao,uf,municipio,cnaes}, nao_criados?[{familia,nome,termos,cnaes,motivo}], pagamento }",
      "url": "https://staging.editalmd.com/api/alertas",
      "auth_detail": "Convidado edm_… em Authorization: Bearer (POST /api/dono, sem cadastro; só o hash fica guardado) ou a sessão da conta, que é dona direto das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. 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, 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,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url}], total, franquia_alertas }",
      "url": "https://staging.editalmd.com/api/alertas",
      "auth_detail": "Convidado edm_… em Authorization: Bearer (POST /api/dono, sem cadastro; só o hash fica guardado) ou a sessão da conta, que é dona direto das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. 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, 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,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url} }",
      "url": "https://staging.editalmd.com/api/alertas/:id",
      "auth_detail": "Convidado edm_… em Authorization: Bearer (POST /api/dono, sem cadastro; só o hash fica guardado) ou a sessão da conta, que é dona direto das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. 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, 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,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url}, itens[{compra_id,status,visto_em,compra}], limite, proximo_antes }",
      "url": "https://staging.editalmd.com/api/alertas/:id/compras",
      "auth_detail": "Convidado edm_… em Authorization: Bearer (POST /api/dono, sem cadastro; só o hash fica guardado) ou a sessão da conta, que é dona direto das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. 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": {
        "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, municípios, exclusões, valores e propostas abertas. PATCH substitui o recorte inteiro; {} limpa."
        },
        "canal": {
          "tipo": "string",
          "desc": "Novo canal: `pull`, `webhook` ou `email` (e-mail verificado da conta; exige sessão).",
          "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, 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,termos,origem,uf,filtros,canal,destino,ativo,pago_ate,ultimo_check,falhas_seguidas,criado_em,alerta_url,compras_url} }",
      "url": "https://staging.editalmd.com/api/alertas/:id",
      "auth_detail": "Convidado edm_… em Authorization: Bearer (POST /api/dono, sem cadastro; só o hash fica guardado) ou a sessão da conta, que é dona direto das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. 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, 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://staging.editalmd.com/api/alertas/:id",
      "auth_detail": "Convidado edm_… em Authorization: Bearer (POST /api/dono, sem cadastro; só o hash fica guardado) ou a sessão da conta, que é dona direto das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. 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. 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."
        },
        "snapshot": {
          "tipo": "Snapshot",
          "desc": "A fotografia inicial da compra."
        },
        "pagamento": {
          "tipo": "object",
          "desc": "`via` (franquia, credito ou x402), `preco_usd` e `pago_ate`."
        }
      },
      "erros": {
        "400": "`compra_id`, canal ou destino inválidos.",
        "401": "Sem token de convidado nem sessão da conta, token desconhecido, 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://staging.editalmd.com/api/vigias",
      "auth_detail": "Convidado edm_… em Authorization: Bearer (POST /api/dono, sem cadastro; só o hash fica guardado) ou a sessão da conta, que é dona direto das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. 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, 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://staging.editalmd.com/api/vigias",
      "auth_detail": "Convidado edm_… em Authorization: Bearer (POST /api/dono, sem cadastro; só o hash fica guardado) ou a sessão da conta, que é dona direto das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. 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, 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://staging.editalmd.com/api/vigias/:id",
      "auth_detail": "Convidado edm_… em Authorization: Bearer (POST /api/dono, sem cadastro; só o hash fica guardado) ou a sessão da conta, que é dona direto das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. 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, 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://staging.editalmd.com/api/vigias/:id/eventos",
      "auth_detail": "Convidado edm_… em Authorization: Bearer (POST /api/dono, sem cadastro; só o hash fica guardado) ou a sessão da conta, que é dona direto das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. 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, 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://staging.editalmd.com/api/vigias/:id",
      "auth_detail": "Convidado edm_… em Authorization: Bearer (POST /api/dono, sem cadastro; só o hash fica guardado) ou a sessão da conta, que é dona direto das listas dela — cookie HttpOnly; escrita com a mesma origem e o X-CSRF-Token de /api/auth/bootstrap. Com o cookie da conta no pedido, quem pede é a conta. Recurso de outro dono responde 404."
    },
    {
      "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",
      "query": {
        "usd": {
          "tipo": "int",
          "desc": "Pacote: 1, 5, 10 ou 25 dólares.",
          "obrigatorio": true
        }
      },
      "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."
        },
        "saldo_em": {
          "tipo": "string",
          "desc": "Onde consultar saldo e extrato."
        }
      },
      "erros": {
        "400": "Pacote fora da lista (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, saldo_em }",
      "url": "https://staging.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 do crédito — as últimas movimentações, sem devolver o token.",
      "grupo": "Crédito",
      "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."
        }
      },
      "erros": {
        "401": "Sem token ou token desconhecido."
      },
      "exemplo": "curl -s $ORIGIN/api/credito -H 'Authorization: Bearer cred_…'",
      "returns": "{ saldo_micros, saldo_usd, criado_em, movimentos }",
      "url": "https://staging.editalmd.com/api/credito",
      "auth_detail": "Token de crédito em `Authorization: Bearer cred_…` (ou header `X-Credito`). Não é conta: é portador de saldo."
    },
    {
      "method": "POST",
      "path": "/api/visit",
      "auth": "none",
      "summary": "Ping da interface que incrementa a visita do dia no painel do operador. Agente não precisa chamar.",
      "grupo": "Operação",
      "desc": "Smoke não conta: `X-MM-Smoke`, User-Agent `mm-smoke` ou `smoke: true` no corpo entram como `counted: false`.",
      "corpo": {
        "p": {
          "tipo": "string",
          "desc": "Caminho da página visitada, só para agrupar."
        },
        "smoke": {
          "tipo": "bool",
          "desc": "`true` marca a chamada como teste e ela fica fora da contagem."
        }
      },
      "body": {
        "p": "/"
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Sempre `true`."
        },
        "counted": {
          "tipo": "bool",
          "desc": "Se a visita entrou na contagem 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\":\"/\"}'",
      "returns": "{ ok, counted, reason? }",
      "url": "https://staging.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": "Contato e proposta de parceria: humano com Turnstile (grátis) ou agente com x402 $0.10.",
      "grupo": "Contato",
      "desc": "O mesmo endereço para dúvida de quem usa e para proposta de patrocínio, parceria ou anúncio (`GET /api/partners` tem os espaços e os preços). Com `tipo`, o assunto identifica a proposta na caixa e o corpo abre com o bloco estruturado. Sem captcha e sem pagamento é 402 com as duas portas.",
      "corpo": {
        "name": {
          "tipo": "string",
          "desc": "Nome de quem escreve (alias `nome`).",
          "obrigatorio": true
        },
        "email": {
          "tipo": "string",
          "desc": "Para onde responder.",
          "obrigatorio": true
        },
        "message": {
          "tipo": "string",
          "desc": "A mensagem (alias `mensagem`).",
          "obrigatorio": true
        },
        "form_ts": {
          "tipo": "int",
          "desc": "Epoch ms de quando o formulário abriu (2 s–12 h). Só o caminho humano exige."
        },
        "tipo": {
          "tipo": "string",
          "desc": "Proposta: `patrocinio`, `parceria` ou `anuncio`. 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": "`ate_100`, `100_500`, `500_2000`, `2000_mais` ou `a_combinar`."
        },
        "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`."
        }
      },
      "retorno": {
        "ok": {
          "tipo": "bool",
          "desc": "Sempre `true` quando a mensagem foi aceita."
        },
        "path": {
          "tipo": "string",
          "desc": "Por onde entrou: `human` com captcha ou `agent` pago."
        }
      },
      "erros": {
        "400": "Validação — o `code` diz o campo.",
        "402": "Agente: pague $0.10 e repita com X-PAYMENT.",
        "403": "Turnstile inválido.",
        "503": "Envio de e-mail indisponível."
      },
      "exemplo": "curl -s -XPOST $ORIGIN/api/contact -H 'content-type: application/json' -d '{\"name\":\"Agente\",\"email\":\"a@example.com\",\"message\":\"proposta de patrocínio\",\"tipo\":\"patrocinio\",\"espaco\":[\"rodape\"],\"duracao\":\"30\"}'",
      "returns": "{ ok, path }",
      "url": "https://staging.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."
        },
        "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."
        }
      },
      "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://staging.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://staging.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": "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 (`UTC`).",
          "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": "Visitantes únicos na borda em 7 dias.",
          "opcional": true
        },
        "pessoas": {
          "tipo": "object",
          "desc": "GA4 quando há: usuários, sessões, países, aparelhos e quem chegou de IA.",
          "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": "Impressões e cliques por patrocinador, quando houver.",
          "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://staging.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://staging.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://staging.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": "O cursor de erro resolvido por produto (`borda`, `cli`) — só com o token do operador.",
      "headers": {
        "Authorization": {
          "tipo": "string",
          "desc": "`Bearer <METRICS_TOKEN>` — a classe operador.",
          "obrigatorio": true
        }
      },
      "retorno": {
        "_texto": "JSON: `{ [produto]: { borda?: 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, cli?: ISO } }`; vazio é `{}`.",
      "url": "https://staging.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": "Parceria, patrocínio e anúncio: os espaços do produto com preço sugerido, os números públicos ao lado e como propor.",
      "desc": "Informação sob consulta, sem ativação: espaços do catálogo da casa com preço em USD por 30 dias (90 e 365 dias com desconto), patrocinadores em vigor, recorte de `/api/vitrine`, carteira da casa (USDC na Base) e o caminho de contato — depósito, PIX ou fatura são combinados na resposta. Cache de 1 hora.",
      "retorno": {
        "status": {
          "tipo": "string",
          "desc": "`sob_consulta`: informação e proposta, sem ativação nem cobrança."
        },
        "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": "Os espaços do produto: `id`, `nome`, `onde`, `formato`, `exclusivo`, `medicao`, `price_usd_30d` (sugestão; `null` é sob consulta), `exposure[{ dias, price_usd }]` para 30, 90 e 365 dias, `disponivel`."
        },
        "house_bundle": {
          "tipo": "object",
          "desc": "O pacote da casa: rodapé e menção para agentes nos dez produtos, com desconto."
        },
        "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": "Como pagar: `rede`, `chain_id`, `ativo`, `pay_to`, `eip681` (a carteira da casa, quando declarada), `alternativas` e a `nota` — depósito, PIX ou fatura pela resposta."
        },
        "contact": {
          "tipo": "object",
          "desc": "`email`, `form_url`, `api_url` (`POST /api/contact` onde há handler), `campos` (os obrigatórios), `campos_proposta` (os opcionais da proposta, com os valores aceitos de cada um), `price_agent_usd`, `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, house_bundle, parcerias, current_sponsors, stats, payment, contact, politica, _links }",
      "url": "https://staging.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/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://staging.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://staging.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."
    },
    {
      "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,instructions,generate_pass,client,guide,workflow,evaluation}, enabled?, id?, status?, granted_credits?, expires_at?, receipt?, via?, message? }",
      "url": "https://staging.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.",
      "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.",
      "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,instructions,generate_pass,client,guide,workflow,evaluation}, enabled?, id?, status?, granted_credits?, expires_at?, receipt?, via?, message? }",
      "url": "https://staging.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/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?,trial?}, pricing, billing, api_index }",
      "url": "https://staging.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?,trial?}, pricing, billing, api_index, payment{provider,mode,network,chain_id,pay_to,homolog,dev,dev_gate,gratis?,facilitator,asset,asset_address,faucet,wallets}, credit{url,header} }",
      "url": "https://staging.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": [
    "avaliacao_cotas",
    "avaliacao_premium",
    "avaliacao_basico",
    "avaliacao_basico_resultado",
    "documentos_empresa",
    "anexar_documento_empresa",
    "remover_documento_empresa",
    "analisar_participacao",
    "consultar_participacao",
    "minhas_empresas",
    "buscar_empresa",
    "adicionar_empresa",
    "selecionar_empresa",
    "remover_empresa",
    "precos_homologados",
    "minha_conta",
    "meus_documentos",
    "meus_compras",
    "documento_vincular",
    "documento_acesso",
    "conta_acompanhamento",
    "conta_vincular_acompanhamento",
    "previa_alerta",
    "editar_alerta",
    "salvas",
    "salvar_compra",
    "remover_salva",
    "gerar_markdown",
    "estado_geracao",
    "criar_cobranca",
    "estado_cobranca",
    "exemplos",
    "documento",
    "documento_dossie",
    "documento_arquivos",
    "api_index",
    "health",
    "buscar_licitacao",
    "prazos",
    "compra",
    "edital_markdown",
    "habilitacao",
    "documento_leitura",
    "criar_dono",
    "dono",
    "rotacionar_segredo_webhook",
    "criar_alerta",
    "alerta_por_cnpj",
    "cnaes",
    "alertas_compras",
    "vigiar_compra",
    "vigia_eventos",
    "credito_saldo",
    "credito_recarregar",
    "recibo",
    "api_access",
    "api_access_buy",
    "pricing",
    "billing"
  ],
  "cota": {
    "free": [
      {
        "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": "cinco 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": "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
      }
    ],
    "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. Cinco 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://staging.editalmd.com/api/"
  }
}