Keybelt
Documentação da API

Do cadastro ao primeiro curl em 60 segundos

Uma chave autentica em todas as APIs do pacote: preencha PDFs com o Fillout e capture screenshots e PDFs da web com o Snapk. REST puro, chave no header, sem SDK obrigatório.

Início rápido

Sua primeira requisição em 3 passos

O Fillout é o caminho mais curto para ver a API funcionando: envie um PDF com campos de formulário e um JSON, receba o PDF preenchido de volta.

1

Crie uma conta grátis

Sem cartão de crédito. O plano Free já dá 100 requisições por mês.

Criar conta
2

Copie sua chave

No painel, sua chave aparece como hk_live_… — copie com um clique.

Abrir painel
3

Rode o curl abaixo

Troque hk_live_… pela sua chave e o arquivo pelo seu PDF. Pronto.

# Preenche um PDF e salva o resultado em preenchido.pdf
curl -X POST https://fillout.haruo.dev/api/v1/fill \
  -H "x-api-key: hk_live_..." \
  -F "[email protected]" \
  -F 'data={"nome":"Ana Souza","cpf":"123.456.789-00","cidade":"São Paulo"}' \
  -o preenchido.pdf

A resposta é o PDF preenchido (application/pdf), entregue como anexo — por isso o -o preenchido.pdf. Não tem um PDF com campos à mão? Comece pelo detect-fields para ver quais campos o seu PDF expõe.

Autenticação

Uma chave, no header, em toda requisição

Toda chamada às rotas /api/ exige a sua chave. Envie-a no header x-api-key ou como Authorization: Bearer — as duas formas são aceitas.

Header x-api-key
curl https://fillout.haruo.dev/api/v1/detect-fields \
  -H "x-api-key: hk_live_..." \
  -F "[email protected]"
Authorization: Bearer
curl https://fillout.haruo.dev/api/v1/detect-fields \
  -H "Authorization: Bearer hk_live_..." \
  -F "[email protected]"

Onde pegar e girar a chave

Crie a conta em /auth/signup e a chave aparece no seu painel como hk_live_…. Ao regenerar a chave, a anterior é revogada na hora e passa a responder 403 — atualize seus serviços com a nova. Guarde a chave em variável de ambiente e nunca a exponha em código de cliente (navegador ou app).

O pacote

Uma chave, todas as ferramentas, uma cota

Fillout e Snapk não são assinaturas separadas. A mesma chave funciona nos dois, e as chamadas somam numa única cota mensal combinada.

Uma chave

hk_live_… autentica no Fillout e no Snapk. Sem contas ou credenciais por serviço.

Cota combinada

Um limite mensal compartilhado entre os produtos. Só requisições bem-sucedidas (status < 400) contam.

Novos produtos incluídos

Quando uma nova API entra no pacote, sua chave já funciona nela — sem migração.

PlanoPreçoCota mensal combinadaRate limit
Free$0100 req / mêspadrão
Pro popular$9 / mês10.000 req / mês60 req / min
Enterprisesob medidailimitadadedicado

Contas novas começam com 14 dias em limites de nível Pro. Depois, sem assinatura, a chave passa a valer os limites do Free.

Referência · Fillout

Preenchimento de PDF

Base URL https://fillout.haruo.dev. Preenche campos de formulário AcroForm — PDFs achatados ou escaneados (sem campos) retornam 422.

POST/api/v1/fill

Envia um PDF com campos AcroForm mais um JSON de valores e retorna o PDF preenchido. Requisição multipart/form-data.

Corpo da requisição

CampoTipoDescrição
fileobrigatórioarquivo (PDF)O PDF a preencher, enviado como parte de arquivo do multipart.
dataobrigatóriostring (JSON)Objeto JSON campo→valor, ex.: {"nome":"Ana"}. Enviado como campo de texto do multipart.

Requisição

curl -X POST https://fillout.haruo.dev/api/v1/fill \
  -H "x-api-key: hk_live_..." \
  -F "[email protected]" \
  -F 'data={"nome":"Ana Souza","cpf":"123.456.789-00"}' \
  -o preenchido.pdf

Resposta

200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="filled-contrato.pdf"

<bytes do PDF preenchido>

Retorna o binário do PDF, não JSON. PDF sem campos AcroForm → 422 UnprocessableEntity.

POST/api/v1/detect-fields

Envia um PDF e recebe a lista de campos AcroForm que ele expõe — útil para descobrir os nomes que você vai passar em /fill.

Corpo da requisição

CampoTipoDescrição
fileobrigatórioarquivo (PDF)O PDF a inspecionar, como parte de arquivo do multipart.

Requisição

cURL
curl -X POST https://fillout.haruo.dev/api/v1/detect-fields \
  -H "x-api-key: hk_live_..." \
  -F "[email protected]"

Resposta

200 OK
{
  "fields": [
    { "name": "nome",   "type": "text",     "rect": [72, 700, 320, 720], "pageNumber": 1 },
    { "name": "cpf",    "type": "text",     "rect": [72, 660, 320, 680], "pageNumber": 1 },
    { "name": "aceito", "type": "checkbox", "rect": [72, 620, 90, 638],  "pageNumber": 1 }
  ],
  "fieldCount": 3
}

type é um de: "text", "checkbox", "radio", "dropdown", "signature". rect e pageNumber podem ser null.

POST/api/v1/fill-with-template

Preenche um template de PDF já armazenado (por ID) com valores em JSON — sem reenviar o arquivo a cada chamada.

Corpo da requisição

CampoTipoDescrição
templateIdobrigatóriostringID do template armazenado.
dataobrigatórioobjectObjeto JSON campo→valor.
flattenopcionalbooleanAchatar o formulário no resultado. Padrão: true.

Requisição

cURL
curl -X POST https://fillout.haruo.dev/api/v1/fill-with-template \
  -H "x-api-key: hk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"templateId":"tpl_123","data":{"nome":"Ana Souza"},"flatten":true}' \
  -o preenchido.pdf

Resposta

200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="filled-<template>.pdf"

<bytes do PDF preenchido>

Existe também /api/v1/fill-with-template/hbs, que aplica o field mapping do template via Handlebars antes de preencher. Mesmo corpo, mesma resposta.

POST/api/v1/templates

Cria um template: envia o PDF e os metadados (multipart). Reuse o ID retornado em /fill-with-template.

Requisição

cURL
curl -X POST https://fillout.haruo.dev/api/v1/templates \
  -H "x-api-key: hk_live_..." \
  -F "[email protected]" \
  -F "name=Contrato padrão" \
  -F "description=Modelo de contrato de prestação de serviços"

Resposta

200 OK
{
  "id": "tpl_123",
  "name": "Contrato padrão",
  "description": "Modelo de contrato de prestação de serviços",
  "field_mapping": "{}",
  "created_at": "2026-07-24T12:00:00.000Z"
}

Status 201 Created. GET /api/v1/templates lista todos os templates.

GETPUTDELETE/api/v1/templates/{id}

Gerencia um template individual: GET retorna seus metadados (id, name, description, pdf_path, field_mapping, created_at, updated_at); PUT atualiza name, description e fieldMapping (JSON); DELETE remove e responde { "success": true }.

Referência · Snapk

Screenshots e HTML → PDF

Base URL https://snapk.haruo.dev. Renderização via navegador headless. Sob carga alta de Chromium, as rotas podem responder 503 com Retry-After.

POST/api/v1/screenshot

Captura o screenshot de uma URL e retorna a imagem PNG.

Corpo da requisição

CampoTipoDescrição
urlobrigatóriostringA URL a capturar.
widthopcionalintegerLargura da viewport (1–7680). Padrão: 1280.
heightopcionalintegerAltura da viewport (1–4320). Padrão: 720.
fullPageopcionalbooleanCapturar a página inteira. Padrão: false.

Requisição

curl -X POST https://snapk.haruo.dev/api/v1/screenshot \
  -H "x-api-key: hk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com","width":1280,"fullPage":true}' \
  -o captura.png

Resposta

200 OK
Content-Type: image/png

<bytes do PNG>

Retorna o binário do PNG. 400 se a URL for inválida; 503 (com Retry-After e retryAfterMs) se a fila do Chromium estiver cheia.

POST/api/v1/pdf

Renderiza HTML como um PDF. Informe html direto ou o nome de um template .hbs; data preenche placeholders {{chave}}.

Corpo da requisição

CampoTipoDescrição
htmlopcionalstringHTML a renderizar. Obrigatório se template não for informado.
templateopcionalstringNome de um template .hbs no servidor. Alternativa a html.
dataopcionalobjectValores para substituir placeholders {{chave}}.
optionsopcionalobjectOpções de página: format (A4), landscape, margin, printBackground, scale.

Requisição

cURL
curl -X POST https://snapk.haruo.dev/api/v1/pdf \
  -H "x-api-key: hk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"html":"<h1>Fatura</h1><p>Total: R$ 100</p>","options":{"format":"A4"}}' \
  -o documento.pdf

Resposta

200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="<timestamp>.pdf"

<bytes do PDF>

Informe html ou template — sem nenhum dos dois, retorna 400. Por segurança, o HTML é renderizado sem acesso à rede (apenas conteúdo inline/data:).

POST/api/v1/url-to-pdf

Abre uma URL num navegador headless e retorna a página como PDF.

Corpo da requisição

CampoTipoDescrição
urlobrigatóriostringA URL a converter em PDF.
optionsopcionalobjectOpções de página (format, landscape, margin, printBackground, scale, waitUntil).

Requisição

cURL
curl -X POST https://snapk.haruo.dev/api/v1/url-to-pdf \
  -H "x-api-key: hk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com","options":{"format":"A4","landscape":false}}' \
  -o pagina.pdf

Resposta

200 OK
Content-Type: application/pdf

<bytes do PDF>

URLs internas/privadas são bloqueadas (proteção contra SSRF) e retornam 400.

Erros e limites

Códigos de erro e a cota mensal

Erros vêm como JSON no formato { statusCode, error, message }. Os campos de autenticação e cota são resolvidos de forma central, iguais para todas as APIs do pacote.

StatusSignificadoQuando acontece
400Bad RequestCorpo/arquivo inválido: JSON malformado no campo data, PDF inválido, URL faltando ou bloqueada.
401UnauthorizedChave ausente ("Missing API key") ou desconhecida ("Invalid API key").
403ForbiddenA chave foi revogada ("API key has been revoked") — regenere e atualize seus serviços.
422Unprocessable EntitySó no Fillout: o PDF não tem campos AcroForm preenchíveis (fieldCount: 0).
429Too Many RequestsCota mensal combinada esgotada. Traz plan, limit, used, resetAt e os headers abaixo.
502Bad GatewaySó no Snapk: a renderização (screenshot/PDF) falhou.
503Service UnavailableSó no Snapk: fila do Chromium cheia. Traz Retry-After e retryAfterMs; repita depois.

Headers de cota em toda resposta

Requisições autenticadas retornam quanto da cota combinada resta. No 429 vem também Retry-After (em segundos).

Headers
X-Quota-Limit: 10000
X-Quota-Used: 42
X-Quota-Reset: 2026-08-01T00:00:00.000Z

Resposta 429

Ao estourar a cota, além dos headers, o corpo detalha o plano e o momento do reset.

429 Too Many Requests
{
  "statusCode": 429,
  "error": "Too Many Requests",
  "message": "Monthly quota exceeded for the 'free' plan (100 requests). Upgrade your plan or wait for the quota to reset.",
  "plan": "free",
  "limit": 100,
  "used": 100,
  "resetAt": "2026-08-01T00:00:00.000Z"
}

A cota é combinada e mensal: chamadas ao Fillout e ao Snapk somam no mesmo limite, e só requisições bem-sucedidas são contabilizadas. Precisa de mais volume? O Pro sobe para 10.000 req/mês.

Ver meu uso

Pegue sua chave e rode o primeiro curl

Conta grátis, sem cartão de crédito. 100 requisições por mês para começar — uma chave para os dois produtos.

Criar conta grátis