Tudo o que o KIT faz, em um lugar só
O ForHosting KIT é um catálogo de 7447 tarefas prontas — converter um documento, ler uma nota fiscal, transcrever áudio, validar um IBAN, gerar um QR Code — em 14 categorias. Você roda tudo aqui pela web, ou chama do seu código com um POST autenticado. Esta página é a referência completa da API: endpoints, o modelo assíncrono, o contrato do webhook, erros e preços.
O que é o KIT
Um catálogo de tarefas, não um modelo
Cada capacidade é uma tarefa: você manda a entrada, recebe o resultado. Não tem token, não tem janela de contexto, não tem engenharia de prompt. Cada tarefa tem preço publicado, unidade documentada e formato fixo.
São quatro jeitos de rodar. Web — cada capacidade tem a sua própria página e roda no navegador; as grátis não saem do seu aparelho. API — um POST autenticado, documentado aqui embaixo. E-mail e Telegram — você manda a tarefa para um endereço do KIT. A API é um canal, não o produto.
Comece por aqui
Do zero ao resultado em três chamadas
Crie a sua conta, pegue a sua chave, rode uma tarefa. Sem ligação de vendas, sem lista de espera.
Pegue uma chave de API
POST /signup com o seu e-mail devolve uma chave que começa com kit_live_. Ela aparece uma vez só. A gente guarda apenas o hash SHA-256 dela, então se você perder não tem como recuperar — a gente emite uma nova.
Escolha uma capacidade
GET /catalog lista as 7447 com preço ao vivo e unidade. Ou veja o catálogo no fim desta página.
Rode
Faça o POST no endpoint da capacidade. Você recebe um task_id na hora e o resultado chega no seu webhook.
Autenticação
Token Bearer, mostrado uma vez só
Toda requisição à API leva Authorization: Bearer kit_live_…. As chaves têm 48 caracteres hexadecimais depois do prefixo.
A gente guarda só o hash SHA-256 da sua chave. Isso é de propósito: um vazamento de banco de dados não entrega a credencial de ninguém — mas também quer dizer que a gente realmente não tem como mandar a sua chave de volta por e-mail. Perdeu? A gente revoga e emite outra.
Chave errada sempre devolve 401 e nunca diz o motivo. Revogada, digitada errada e nunca existiu são indistinguíveis de propósito: contar para você qual foi é contar para um atacante também.
O modelo assíncrono
Toda tarefa é assíncrona. Sem exceção.
Você faz o POST da tarefa
Devolve 202 com um task_id e status queued, mais quanto vai custar. O valor fica reservado, não cobrado.
Ela roda na borda (edge)
Menos de um segundo nas tarefas de computação; alguns segundos em IA e mídia.
O resultado vai atrás de você
Ele é enviado por POST para a sua webhook_url, se você tiver informado uma. Se não, GET /tasks/{id}/result. Os resultados ficam guardados conforme o tamanho: de 168 h para os pequenos (até 1 MB) a 6 h para os maiores.
Falha não custa nada
A tarefa é tentada até 3 vezes no total, com backoff entre as tentativas. Se ainda assim falhar, a reserva é liberada e você não paga. Nunca.
Referência da API
Todos os endpoints que o KIT responde
As rotas não têm prefixo de versão. /v1/* continua resolvendo para clientes antigos, mas não é a forma canônica e código novo não deve usar.
URL base: https://api.kit.forhosting.com
| Método | Rota | Auth | O que faz |
|---|---|---|---|
ANY |
/ |
Pública | Índice do serviço: versão, número de capacidades e a lista de endpoints que a API anuncia sobre si mesma. Sem chave, e responde a qualquer método. |
POST |
/{alias} |
Chave de API | Atalho por capacidade para POST /tasks com o type fixo — por exemplo POST /ocr/invoice. É a forma que cada página de capacidade mostra. |
GET |
/account |
Chave de API | Saldo da conta: available_usd é o saldo real da carteira, mais held_usd. Quando a carteira é gerida pela área do cliente, balance.source é "portal" e balance_endpoint aponta para o valor ao vivo. |
POST |
/agent/ask |
Chave de API Em breve | Não implementado — devolve 501 com chave e 401 sem ela. O assistente conversacional está sendo construído à parte; para achar uma capacidade use POST /catalog/search. |
GET |
/catalog |
Pública | Todas as capacidades com preço e unidade ao vivo. ?lang=en|es, ?q= para filtrar, ?limit=, ?schema=1 para o schema de entrada e ?channel= para receber o preço já ajustado àquele canal — peça o canal pelo qual você vai cobrar, ou vai mostrar um valor e cobrar outro. |
POST |
/catalog/search |
Pública | {query} → as capacidades que combinam, cada uma com o preço já redigido. Sem chave. Pontua por cobertura de palavra inteira com limiar, então uma busca que ele não entende devolve nada em vez de chutar — é de propósito. |
POST |
/estimate |
Chave de API | {type, input} → unidades, preço e detalhamento. Cota sem executar. Quando a quantidade real não dá para saber antes (o número de páginas de um PDF atrás de uma URL), a resposta avisa com estimated: true. |
GET |
/mobile/bootstrap |
Pública | O que o app precisa para iniciar: categorias, rótulos e os mesmos preços ajustados ao canal. Sem chave. Também não faz parte do contrato público, pelo mesmo motivo. |
GET |
/mobile/catalog |
Pública | Projeção do catálogo para o app, com os preços já ajustados ao canal do app. Sem chave. Não faz parte do contrato público: o formato acompanha o app e pode mudar sem aviso — programe contra GET /catalog. |
GET |
/plans |
Pública | Valores de recarga: currency e topup (sku, default_amount, min_amount). Nada mais — não há planos para assinar. |
POST |
/signup |
Pública | {email} → 201 com a sua api_key, mostrada uma única vez. 409 se o e-mail já existe; 429 acima de 10/h por IP. |
GET |
/tasks |
Chave de API | As suas tarefas. ?status=, ?limit= (25 por padrão, 100 no máximo). |
POST |
/tasks |
Chave de API | {type, input, webhook_url?, max_cost_usd?} → 202. Você paga pela unidade real da tarefa — páginas, minutos, imagens — medida durante a execução, não pela estimativa prévia. max_cost_usd é um teto duro: se o custo real passar dele, a tarefa falha e nada é cobrado. Mande Idempotency-Key para que repetir seja seguro: uma repetição devolve a tarefa original com idempotent: true. |
DELETE |
/tasks/{id} |
Chave de API | Cancela uma tarefa na fila e libera a reserva dela. |
GET |
/tasks/{id} |
Chave de API | Estado da tarefa. 10 consultas a cada 10 segundos por tarefa; acima disso, 429 com Retry-After: 1. Prefira o webhook. |
GET |
/tasks/{id}/events |
Chave de API Em breve | Não implementado — devolve 501. O SSE vem depois; use o webhook. |
GET |
/tasks/{id}/result |
Chave de API | Resultado JSON, ou o arquivo como anexo. 409 se não está pronto, 410 se expirou, 422 se falhou. A retenção depende do tamanho do resultado: 168 h para os pequenos, até 6 h para os muito grandes. |
POST |
/tasks/{id}/retry |
Chave de API | Recoloca na fila uma tarefa que falhou. |
POST |
/uploads |
Chave de API | Mande um arquivo local: corpo binário cru, com o Content-Type do arquivo. → 201 com ref: "kit://upl_…", que você depois põe onde iria uma URL: {"input": {"pdf": "kit://upl_…"}}. Um upload pode alimentar várias tarefas. Os refs vivem 24 h. Máximo 100 MiB (104.9 MB) por upload; cada capacidade aplica ainda o seu próprio limite. |
Webhooks
Entrega assinada — e como conferir a assinatura
Informe webhook_url ao criar a tarefa e a gente faz o POST do resultado lá quando ficar pronto. É o caminho recomendado: custa menos que polling e chega antes.
Confira a assinatura antes de confiar no corpo. Toda entrega leva KIT-Signature: v1=<hex> e KIT-Timestamp: <segundos unix>. A assinatura é um HMAC-SHA256 sobre a string <timestamp>.<corpo cru> — o timestamp e o ponto fazem parte do payload assinado, não são enfeite. Assine os bytes crus que você recebeu, não um objeto re-serializado.
A entrega é tentada até 5 vezes, com backoff exponencial. Um 4xx vindo do seu endpoint interrompe as tentativas na hora — a gente lê isso como “o seu handler está errado”, não como “tente mais tarde”. Só 5xx e erro de rede geram nova tentativa. Depois disso, a entrega vai para a dead-letter.
O que a gente manda no POST
{
"event": "task.completed",
"created_at": "2026-07-16T10:31:04.120Z",
"data": {
"task_id": "tsk_a1b2c3d4e5f6",
"type": "ocr.invoice",
"status": "done",
"units": 1,
"price_usd": 0.021,
"result_url": "https://api.kit.forhosting.com/tasks/tsk_a1b2c3d4e5f6/result"
}
}{
"event": "task.failed",
"created_at": "2026-07-16T10:31:04.120Z",
"data": {
"task_id": "tsk_a1b2c3d4e5f6",
"type": "ocr.invoice",
"status": "failed",
"error": {
"code": "engine_error",
"message": "Upstream timed out after 3 attempts."
},
"charged": false
}
}Conferindo a assinatura
const crypto = require("crypto");
// req.body tiene que ser el cuerpo CRUDO, no un objeto re-serializado.
function verify(rawBody, headers, secret) {
const sig = (headers["kit-signature"] || "").replace(/^v1=/, "");
const ts = headers["kit-timestamp"];
const mine = crypto.createHmac("sha256", secret)
.update(ts + "." + rawBody) // el timestamp va firmado
.digest("hex");
return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(mine));
}import hmac, hashlib
def verify(raw_body: bytes, headers, secret: str) -> bool:
sig = headers["KIT-Signature"].removeprefix("v1=")
ts = headers["KIT-Timestamp"]
mine = hmac.new(secret.encode(),
f"{ts}.".encode() + raw_body, # el timestamp va firmado
hashlib.sha256).hexdigest()
return hmac.compare_digest(sig, mine)Erros
HTTP padrão, slug legível por máquina
Todo erro traz no corpo um slug estável em error. Trate pelo slug, não pela mensagem: as mensagens são traduzidas e podem mudar.
| HTTP | Erro | O que significa |
|---|---|---|
400 | flow_depth | Uma capacidade composta aninhou mais fundo do que o permitido. Achate os passos. |
400 | invalid_amount | O valor está faltando, não é número, ou está fora da faixa permitida. |
400 | invalid_email | O e-mail está ausente ou é inválido. |
400 | invalid_input | Falta um campo obrigatório na entrada, ou ela não está no formato que esta tarefa espera. |
400 | invalid_json | O corpo da requisição não é um JSON válido. |
400 | missing_type | Falta o campo 'type' na requisição. Consulte GET /catalog. |
400 | unknown_op | Operação desconhecida para esta capacidade. Confira o nome no catálogo. |
400 | unsafe_url | A URL aponta para um lugar de onde não vamos baixar: um endereço interno ou não público. |
401 | auth_required | Este passo precisa de uma conta identificada e a requisição não traz nenhuma. |
401 | no_key | A requisição não traz API key, ou a conta não tem nenhuma ativa. |
401 | unauthorized | Token ausente ou inválido. Confira o header Authorization. |
402 | account_suspended | Sua conta está suspensa, normalmente pelo limite de gasto. Fale com a gente para reativá-la. |
402 | insufficient_balance | Saldo insuficiente para esta tarefa. Faça uma recarga e tente de novo. |
402 | max_cost_exceeded | A tarefa custou mais do que o max_cost_usd que você definiu. Nada foi cobrado. |
403 | forbidden | A credencial é válida, mas não tem permissão para isso. |
404 | input_not_found | Essa referência kit:// não existe. Envie o arquivo de novo com POST /uploads. |
404 | not_found | Não há tarefa nem recurso nesse caminho. |
404 | unknown_type | Esse tipo de tarefa não existe. Confira o campo type no catálogo. |
409 | alias_taken | Esse alias de e-mail de entrada é de outra pessoa. Escolha outro. |
409 | already_accepted | Esse aceite já foi usado. Cada um vale exatamente uma vez. |
409 | email_taken | Já existe uma conta com esse e-mail. |
409 | need_lease | Outro worker já está rodando esta tarefa. Espere terminar. |
409 | not_cancellable | A tarefa não está mais na fila, então não dá para cancelar. Só as que estão na fila. |
409 | not_ready | A tarefa ainda não terminou. Consulte o status ou aguarde o webhook. |
409 | not_retryable | Só tarefas que falharam podem ser repetidas. Esta está em outro estado. |
410 | expired | A janela de retenção do resultado já passou e ele não fica mais guardado. |
410 | input_expired | Essa referência kit:// expirou. Os envios duram 24 h; envie o arquivo de novo. |
410 | quote_expired | A cotação passou da validade. Peça uma nova. |
413 | input_too_large | A entrada passou do tamanho máximo desta tarefa. Confira os limites publicados. |
413 | resolution_too_high | A imagem ou o vídeo passam da resolução que esta capacidade aceita. |
422 | conversion_failed | Não deu para converter o arquivo. Normalmente é formato corrompido ou inesperado. |
422 | engine_error | O motor falhou em todas as tentativas. A reserva foi liberada: você não paga. |
422 | needs_rework | O resultado não passou no próprio controle de qualidade, então não é entregue. Não é cobrado. |
429 | rate_limited | Muitas requisições em pouco tempo. Espere um instante e tente de novo. |
500 | lease_error | Não deu para tomar a tarefa para executar. Ela volta para a fila. |
500 | ledger_error | Não foi possível reservar nem liquidar o saldo. Tente de novo. |
500 | no_hold | A tarefa não tem reserva para liquidar. Não deveria acontecer; se acontecer, nos avise. |
500 | no_result | A tarefa terminou sem produzir resultado. |
501 | coming_soon | Esta capacidade ainda não está no ar. Em breve ela chega. |
501 | mail_not_configured | Esta capacidade manda e-mail e a conta ainda não tem remetente configurado. |
501 | not_implemented | Este endpoint ou capacidade ainda não está disponível. |
501 | tickets_not_configured | A integração de tíquetes não está configurada para esta conta. |
501 | unsupported | Esta operação ainda não é suportada (por exemplo, os flows não podem ser cotados). |
502 | model_output_invalid | O modelo devolveu algo que não bate com a saída declarada. Não é cobrado. |
502 | tickets_unreachable | O sistema de tíquetes não respondeu. Nada foi cobrado; tente de novo. |
503 | all_busy | Todos os workers desta capacidade estão ocupados. Tente de novo em instantes. |
Preços
Publicado, por tarefa, sem créditos
Pague apenas pelo que usar. Adicione saldo à sua conta (a partir de US$ 10,00) — ele nunca expira — e cada tarefa é descontada dele pelo preço publicado por tarefa. Dólares de verdade, não pontos.
Cada tarefa custa uma taxa base mais uma taxa por unidade, as duas publicadas na página da própria capacidade e no catálogo aqui embaixo — a partir de US$ 0,002 por chamada. POST /estimate faz o orçamento da tarefa sem rodar, e max_cost_usd na tarefa recusa a execução se ela for custar mais do que você disse.
Tarefa que falha não é cobrada. As capacidades grátis rodam no seu navegador e não custam absolutamente nada.
Limites
O que o serviço aplica
São três limites, e cada um conta de um jeito. Por conta: 600 requisições por minuto no total e 60 uploads por minuto. Por tarefa: 10 consultas de status a cada 10 segundos — passou de qualquer um deles, você recebe 429 com Retry-After: 1. Use o webhook em vez de ficar consultando: custa menos e chega antes. Os resultados ficam guardados conforme o tamanho: 168 h até 1 MB e 6 h para os muito grandes. GET /tasks devolve 25 por padrão e 100 no máximo. O signup é limitado a 10 contas por hora por IP.
Catálogo de capacidades
Todas as 7447, navegáveis por categoria
Cada capacidade tem a sua própria página, onde você roda, vê um exemplo de verdade e o preço publicado — o mesmo que esta API cobra. Abra o catálogo completo, ou vá direto para uma categoria.
Sem garantia
O que a gente não promete
O KIT é fornecido “no estado em que está”: sem garantia, sem compromisso de disponibilidade, sem SLA (infraestrutura dedicada com SLA é um adicional pago) e sem suporte garantido. A cláusula completa do KIT está nos Termos.