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:

terminal
curl "https://api.pncp.dev/api/consulta/v1/contratacoes/publicacao?dataInicial=20260907&dataFinal=20260913&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:

header
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:

na URL, para testar
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:

/api/consulta/v1/contratacoes/publicacao
O que devolve
licitações publicadas num período
/api/consulta/v1/contratacoes/proposta
O que devolve
licitações com proposta ainda aberta
/api/consulta/v1/contratos
O que devolve
contratos assinados
/api/consulta/v1/atas
O que devolve
atas de registro de preço
/api/consulta/v1/orgaos/{cnpj}/compras/{ano}/{seq}
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:

resposta
x-quota-limit: 100000
x-quota-remaining: 99994
x-quota-reset: 1790823600
x-pncp-dev: hit

O x-pncp-dev diz o que aconteceu com a sua chamada:

  • hitbuscamos no PNCP agora
  • cacheveio da cópia que a gente guardou
  • authfaltou a chave, ou ela não vale mais
  • quotaacabou a cota do mês ou o limite por minuto
  • deniedessa rota não é pública
  • methodsó GET passa por aqui
  • waf-blockedo PNCP recusou, mesmo depois de tentarmos de novo
  • upstream-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:

429
{
  "error": {
    "code": "QUOTA_EXCEEDED",
    "message": "Cota mensal esgotada. Compre um pacote ou aguarde o próximo mês.",
    "resetAt": 1790823600
  }
}

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.

O 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.