Documentação
O pncp.dev repassa as rotas públicas do PNCP. Se você já sabe chamar o pncp.gov.br, já sabe usar isto: troque o endereço e mande a sua chave num header.
Começar
Crie a sua chave no painel. Leva um minuto e não pede cartão. Depois é só chamar:
curl "https://api.pncp.dev/api/consulta/v1/contratacoes/publicacao?dataInicial=20261022&dataFinal=20261028&codigoModalidadeContratacao=6&pagina=1&tamanhoPagina=10" \
-H "x-api-key: $PNCP_API_KEY"A resposta é o JSON do PNCP, sem nenhuma alteração.
Sua chave
Toda chamada precisa da sua chave. O melhor jeito de mandar é no header x-api-key:
x-api-key: pncp_a1b2c3d4e5f6...Para um teste rápido, a chave também pode ir na URL, no parâmetro api_key. Serve para uma aba do navegador ou para uma ferramenta que não deixa mexer em header:
curl "https://api.pncp.dev/api/consulta/v1/orgaos?pagina=1&api_key=$PNCP_API_KEY"A gente tira esse parâmetro da URL antes de tudo: ele nunca chega no PNCP e não entra no cache. Ainda assim, no seu código prefira o header. URL fica salva no histórico do navegador e costuma aparecer em log de erro.
A chave inteira aparece uma vez só, na hora que você cria. Depois o painel mostra só o começo dela. Perdeu? Crie outra e revogue a antiga. Você pode ter várias ao mesmo tempo, uma para cada ambiente.
Rotas
Qualquer rota que comece com /api/ no PNCP funciona aqui, com os mesmos parâmetros. As mais usadas:
- O que devolve
- licitações publicadas num período
- O que devolve
- licitações com proposta ainda aberta
- O que devolve
- contratos assinados
- O que devolve
- atas de registro de preço
- O que devolve
- detalhe de uma compra
Os parâmetros são os mesmos do PNCP: data em AAAAMMDD, tamanhoPagina de 10 para cima. Para saber o que cada campo significa, vale a documentação oficial do PNCP.
Cota e limites
Cada chamada desconta uma requisição da sua cota do mês. A cota zera todo dia 1º, no horário de Brasília. O plano grátis dá 100.000 requisições por mês.
Quando a cota acaba, seus créditos entram no lugar sozinhos e nada para. Sem cota e sem crédito, a resposta é 429, com a data em que a cota volta.
Também existe um limite por minuto, contado por chave, para não sobrecarregar o PNCP. Ele só conta as chamadas que chegam lá: resposta que veio do cache não gasta esse limite.
Chamada recusada também desconta. Passou do limite por minuto, acabou a cota, o PNCP falhou: cada tentativa conta uma requisição. É isso que segura um loop que saiu do controle antes de ele pesar no PNCP.
Cache
A gente guarda cada resposta por 5 minutos. Nesse tempo, quem pedir a mesma coisa recebe na hora, sem ir até o PNCP. Ainda assim desconta da sua cota: a chamada foi sua.
O que vem na resposta
Toda resposta que deu certo traz o saldo da sua cota nos headers, para você acompanhar sem abrir o painel:
x-quota-limit: 100000
x-quota-remaining: 99994
x-quota-reset: 1793502000
x-pncp-dev: hitO x-pncp-dev diz o que aconteceu com a sua chamada:
hitbuscamos no PNCP agoracacheveio da cópia que a gente guardouauthfaltou a chave, ou ela não vale maisquotaacabou a cota do mês ou o limite por minutodeniedessa rota não é públicamethodsó GET passa por aquiwaf-blockedo PNCP recusou, mesmo depois de tentarmos de novoupstream-erroro PNCP não respondeu, ou a falha foi nossa
Erros
Os erros que são nossos vêm em JSON. O code nunca muda, então dá para o seu programa decidir o que fazer; a mensagem em português é para você ler no log:
{
"error": {
"code": "QUOTA_EXCEEDED",
"message": "Cota mensal esgotada. Compre um pacote ou aguarde o próximo mês.",
"resetAt": 1793502000
}
}Erro que vem do próprio PNCP (uma data errada, por exemplo) chega até você do jeito que ele mandou, com o status original. A gente não mexe na resposta do PNCP.
Status e filas
O status é público, sem chave e sem desconto na cota. A mesma medição aparece em /status e no JSON:
curl "https://api.pncp.dev/_/status"Escolha pelo caminho da chamada, não pelo nome da sua fila. Uma tarefa chamada "detail" pode usar /api/consulta/v1/:
pncp-dev- O que é testado
- Roteador da API e leitura do banco do pncp.dev. Teste interno, sem DNS nem conexão externa.
pncp-site- O que é testado
- Página inicial do pncp.dev pela rede. Sua falha não pausa chamadas à API.
pncp-search- O que é testado
- /api/search/: uma busca com uma resposta por página.
pncp-consulta- O que é testado
- /api/consulta/v1/: os detalhes de uma compra publicada.
pncp-items- O que é testado
- /api/pncp/v1/: os itens de uma compra publicada.
O JSON tem schemaVersion: 1, now,pollAfterSeconds: 60 e uma lista components. Os horários são segundos desde 1970, no padrão UNIX. Cada componente traz:
status:operational,downouunknown(sem medição válida).checkedAt: início do último teste.expiresAt: esse horário mais 180 segundos. Sem teste, ambos sãonull.ready: só étruese o serviço e a API com o banco estiverem respondendo com medições válidas.readyUntil: até quando esse sinal vale. É o primeiro vencimento entre o teste do serviço e o da API com o banco. Valenullquando não está pronto.httpStatus,latencyMseerror: última resposta, tempo em milissegundos e motivo da falha. Sem resposta HTTP,httpStatusénull.
Uma leitura do status retorna HTTP 200 mesmo quando um serviço está fora do ar. O status geral pode ser degraded quando só parte falha. Para decidir sobre uma tarefa, use o componente dela, não o HTTP 200 nem o status geral.
async function canStart(service) {
try {
const response = await fetch("https://api.pncp.dev/_/status", {
signal: AbortSignal.timeout(5000),
cache: "no-store"
});
if (!response.ok) return false;
const status = await response.json();
if (status.schemaVersion !== 1 || !Array.isArray(status.components)) return false;
const component = status.components.find(c => c.id === service);
return component?.ready === true
&& Number.isFinite(component.readyUntil)
&& Date.now() / 1000 < component.readyUntil;
} catch {
return false;
}
}
console.log(await canStart("pncp-consulta")); // true ou falseConsulte a cada 60 segundos e compartilhe o resultado entre os consumidores da fila, em vez de consultar por tarefa. Mesmo com um resultado salvo, confirareadyUntil antes de iniciar cada tarefa.
Adiar não é falhar
Se vier ready: false, se o prazo vencer ou se o status não responder, adie só as tarefas desse serviço, sem gastar uma tentativa. Confira de novo em um minuto. Retome quando vier uma medição nova e válida. Nunca descarte a tarefa.
O teste usa o mesmo acesso ao PNCP das chamadas reais, com nova tentativa e caminho alternativo quando cabem, mas sem respostas guardadas. Exigimos sucesso HTTP e JSON com os campos esperados. Um 403, 429, 503 ou uma página de bloqueio não conta como disponível. Testar uma rota não garante que todas as outras estão funcionando.
O status não substitui o tratamento de erro de cada chamada. Uma falha pode começar entre dois testes. Se a API ou o banco cair, o status também pode ficar inacessível: nesse caso, pause as tarefas até conseguir confirmar de novo.
Agentes de IA (MCP)
Conecte seu app de IA para consultar licitações, contratos e atas do PNCP ou conferir a cota da sua conta. O acesso é somente leitura.
Ver como conectar seu app de IAO que não dá para fazer
- Só GET. Aqui só se consulta dado público. POST, PUT e DELETE recebem
405. - Só rotas
/api/. O resto do site do PNCP não passa por aqui. - Nada de área logada do gov.br. A gente nunca repassa o header
Authorization. Por isso a API de envio de dados do PNCP não funciona aqui, e isso é de propósito.