ForHosting KIT

Todo lo que hace el KIT, en un solo lugar

ForHosting KIT es un catálogo de 7447 tareas listas — convertir un documento, leer una factura, transcribir audio, validar un IBAN, generar un QR — repartidas en 14 categorías. Las ejecuta aquí en la web o las llama desde su código con un POST autenticado. Esta página es la referencia completa de la API: endpoints, modelo asíncrono, contrato de webhooks, errores y precios.

Úselo desde WebAPIEmailTelegramApp pronto

Qué es el KIT

Un catálogo de tareas, no un modelo

Cada capacidad es una tarea: manda una entrada y recibe un resultado. No hay tokens, ni ventana de contexto, ni prompt engineering. Una tarea tiene precio publicado, unidad documentada y forma fija.

Cuatro formas de ejecutarla. Web — cada capacidad tiene su página y corre en el navegador; las gratuitas no salen de su dispositivo. API — un POST autenticado, documentado abajo. Email y Telegram — manda la tarea a una dirección del KIT. La API es un canal, no el producto.

Empezar

De cero a un resultado en tres llamadas

Crea la cuenta, recoge la clave, ejecuta. Sin llamada comercial ni lista de espera.

1

Consiga una API key

POST /signup con su email devuelve una clave que empieza por kit_live_. Se enseña una sola vez. Solo guardamos su hash SHA-256, así que si la pierde no podemos recuperarla — emitimos otra.

2

Elija una capacidad

GET /catalog lista las 7447 con su precio y unidad en vivo. O mire el catálogo al final de esta página.

3

Ejecútela

POST al endpoint de la capacidad. Recibe un task_id al instante y el resultado llega a su webhook.

Autenticación

Token Bearer, se enseña una vez

Toda petición a la API lleva Authorization: Bearer kit_live_…. Las claves son 48 caracteres hexadecimales tras el prefijo.

Guardamos solo el hash SHA-256 de su clave. Es a propósito: un volcado de la base de datos no le entrega sus credenciales a nadie — pero también significa que de verdad no podemos reenviársela. ¿La perdió? Revocamos y emitimos otra.

Una clave mala siempre devuelve 401 y nunca dice por qué. Revocada, mal escrita e inexistente son indistinguibles a propósito: decirte cuál era se lo dice también a quien está probando.

El modelo asíncrono

Toda tarea es asíncrona. Sin excepciones.

1

Hace POST de la tarea

Devuelve 202 con un task_id y estado queued, más lo que va a costar. El dinero se retiene, no se cobra.

2

Se ejecuta en el edge

Sub-segundo en cómputo; segundos en IA y medios.

3

El resultado te busca

Se hace POST a tu webhook_url si diste uno. Si no, GET /tasks/{id}/result. Los resultados se guardan según su tamaño: desde 168 h para los pequeños (hasta 1 MB) hasta 6 h para los más grandes.

4

Fallar no cuesta

Una tarea se intenta hasta 3 veces en total, con backoff entre intentos. Si aun así falla, se libera la retención y no se te cobra. Nunca.

Referencia de la API

Todos los endpoints que responde el KIT

Las rutas no llevan prefijo de versión. /v1/* sigue resolviendo por compatibilidad, pero no es la forma canónica y el código nuevo no debería usarla.

POSThttps://api.kit.forhosting.com/tasks

URL base: https://api.kit.forhosting.com

MétodoRutaAuthQué hace
ANY / Pública Índice del servicio: versión, número de capacidades y la lista de endpoints que el API anuncia de sí mismo. Sin clave, y responde a cualquier método.
POST /{alias} API key Atajo por capacidad de POST /tasks con el type fijo — p.ej. POST /ocr/invoice. Es la forma que enseña cada página de capacidad.
GET /account API key Saldo de la cuenta: available_usd es el saldo real del monedero, más held_usd. Si el monedero lo gestiona el área de cliente, balance.source es "portal" y balance_endpoint apunta al valor en vivo.
POST /agent/ask API key Pronto No implementado — devuelve 501 con clave y 401 sin ella. El asistente conversacional se está construyendo aparte; para encontrar una capacidad use POST /catalog/search.
GET /catalog Pública Todas las capacidades con precio y unidad en vivo. ?lang=en|es, ?q= para filtrar, ?limit=, ?schema=1 para el esquema de entrada y ?channel= para recibir el precio ya ajustado a ese canal — pida el canal por el que va a facturar, o enseñará una cifra y cobrará otra.
POST /catalog/search Pública {query} → las capacidades que encajan, cada una con su precio ya redactado. Sin clave. Puntúa por cobertura de palabra entera con umbral, así que una consulta que no entiende devuelve nada en vez de adivinar — es a propósito.
POST /estimate API key {type, input} → unidades, precio y desglose. Cotiza sin ejecutar. Cuando la cantidad real no se puede saber de antemano (las páginas de un PDF que llega por URL), la respuesta avisa con estimated: true.
GET /mobile/bootstrap Pública Lo que la app móvil necesita para arrancar: categorías, etiquetas y los mismos precios ajustados al canal. Sin clave. Tampoco forma parte del contrato público, por el mismo motivo.
GET /mobile/catalog Pública Proyección del catálogo para la app móvil, con los precios ya ajustados al canal de la app. Sin clave. No forma parte del contrato público: su forma sigue a la app y puede cambiar sin aviso — programe contra GET /catalog.
GET /plans Pública Importes de recarga: currency y topup (sku, default_amount, min_amount). Nada más — no hay planes a los que suscribirse.
POST /signup Pública {email}201 con tu api_key, mostrada una vez. 409 si el email ya existe; 429 pasadas 10/h por IP.
GET /tasks API key Tus tareas. ?status=, ?limit= (25 por defecto, 100 máximo).
POST /tasks API key {type, input, webhook_url?, max_cost_usd?}202. Se factura por la unidad real de la tarea — páginas, minutos, imágenes — medida al ejecutarla, no por la estimación previa. max_cost_usd es un tope duro: si el coste real lo supera, la tarea falla y no se cobra nada. Manda Idempotency-Key para que reintentar sea seguro: una repetición devuelve la tarea original con idempotent: true.
DELETE /tasks/{id} API key Cancela una tarea en cola y libera su retención.
GET /tasks/{id} API key Estado de la tarea. 10 consultas cada 10 segundos por tarea; por encima, 429 con Retry-After: 1. Mejor use el webhook.
GET /tasks/{id}/events API key Pronto No implementado — devuelve 501. El SSE llegará; usa el webhook.
GET /tasks/{id}/result API key Resultado JSON, o el fichero como adjunto. 409 si no está listo, 410 si caducó, 422 si falló. La retención depende del tamaño del resultado: 168 h para los pequeños, hasta 6 h para los muy grandes.
POST /tasks/{id}/retry API key Reencola una tarea fallida.
POST /uploads API key Manda un archivo local: cuerpo binario crudo, con el Content-Type del archivo. → 201 con ref: "kit://upl_…", que luego pones donde iría una URL: {"input": {"pdf": "kit://upl_…"}}. Una subida puede alimentar varias tareas. Los refs viven 24 h. Máximo 100 MiB (104.9 MB) por subida; cada capacidad aplica además su propio límite.

Webhooks

Entrega firmada, y cómo verificarla

Pon webhook_url al crear la tarea y hacemos POST del resultado ahí cuando está listo. Es la vía recomendada: cuesta menos que sondear y llega antes.

Verifica la firma antes de fiarte del cuerpo. Cada entrega lleva KIT-Signature: v1=<hex> y KIT-Timestamp: <segundos unix>. La firma es HMAC-SHA256 sobre la cadena <timestamp>.<cuerpo crudo> — el timestamp y el punto son parte de lo firmado, no adorno. Firma los bytes crudos que recibiste, no un objeto re-serializado.

La entrega se intenta hasta 5 veces con backoff exponencial. Un 4xx desde su endpoint corta los reintentos de inmediato — lo leemos como «su handler está mal», no como «pruebe luego». Solo se reintentan los 5xx y los errores de red. Después, la entrega va a la cola de fallidos.

{
  "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"
  }
}
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));
}

Errores

HTTP estándar, slug legible por máquina

Todo error lleva un error estable en el cuerpo. Compara contra el slug, no contra el mensaje: los mensajes están localizados y pueden cambiar.

HTTPErrorSignificado
400flow_depthUna capacidad compuesta se anidó más de lo permitido. Aplane los pasos.
400invalid_amountEl importe falta, no es un número, o está fuera del rango permitido.
400invalid_emailEl email falta o no es válido.
400invalid_inputAl input le falta un campo obligatorio o no tiene la forma que espera esta tarea.
400invalid_jsonEl cuerpo de la petición no es JSON válido.
400missing_typeFalta el campo 'type' en la petición. Consulte GET /catalog.
400unknown_opOperación desconocida para esta capacidad. Compruebe el nombre contra el catálogo.
400unsafe_urlLa URL apunta a un sitio del que no vamos a descargar: una dirección interna o no pública.
401auth_requiredEste paso necesita una cuenta identificada y la petición no la trae.
401no_keyLa petición no trae API key, o la cuenta no tiene ninguna activa.
401unauthorizedAPI key ausente o inválida.
402account_suspendedSu cuenta está suspendida, normalmente por el tope de gasto. Escríbanos para reactivarla.
402insufficient_balanceEl saldo no cubre el precio de la tarea.
402max_cost_exceededLa tarea costó más que el max_cost_usd que fijaste. No se ha cobrado nada.
403forbiddenLa credencial es válida pero no tiene permiso para esto.
404input_not_foundEsa referencia kit:// no existe. Vuelve a subir el archivo con POST /uploads.
404not_foundNo hay ninguna tarea ni recurso en esa ruta.
404unknown_typeEl tipo de tarea no existe.
409alias_takenEse alias de correo entrante es de otra persona. Elija otro.
409already_acceptedEsa aceptación ya se usó. Cada una vale exactamente una vez.
409email_takenYa existe una cuenta con ese email.
409need_leaseOtro trabajador ya está ejecutando esta tarea. Espere a que termine.
409not_cancellableLa tarea ya no está en cola, así que no se puede cancelar. Solo se cancelan las encoladas.
409not_readyLa tarea aún no ha terminado. Sondee su estado o espere el webhook.
409not_retryableSolo se reintentan las tareas fallidas. Esta está en otro estado.
410expiredLa ventana de retención del resultado ya pasó y no se conserva.
410input_expiredEsa referencia kit:// caducó. Las subidas viven 24 h; vuelve a subir el archivo.
410quote_expiredLa cotización pasó su ventana de validez. Pida una nueva.
413input_too_largeEl archivo supera el límite de tamaño.
413resolution_too_highLa imagen o el vídeo superan la resolución que acepta esta capacidad.
422conversion_failedNo se pudo convertir el fichero. Suele ser un formato corrupto o inesperado.
422engine_errorEl motor falló en todos los intentos. Se liberó la retención: no se le cobra.
422needs_reworkEl resultado no pasó su propio control de calidad, así que no se entrega. No se cobra.
429rate_limitedDemasiadas peticiones. Use el webhook en vez de sondear.
500lease_errorNo se pudo tomar la tarea para ejecutarla. Vuelve a la cola.
500ledger_errorNo se pudo reservar ni liquidar el saldo. Inténtelo de nuevo.
500no_holdLa tarea no tiene reserva que liquidar. No debería ocurrir; si ocurre, avísenos.
500no_resultLa tarea terminó sin producir resultado.
501coming_soonCapacidad en despliegue (Fase 1b). Su landing existe; aún no acepta ejecuciones.
501mail_not_configuredEsta capacidad envía correo y la cuenta aún no tiene remitente configurado.
501not_implementedEste endpoint o capacidad aún no está disponible.
501tickets_not_configuredLa integración de tiques no está configurada para esta cuenta.
501unsupportedEsta operación aún no se admite (por ejemplo, los flows no se pueden cotizar).
502model_output_invalidEl modelo devolvió algo que no encaja con la salida declarada. No se cobra.
502tickets_unreachableEl sistema de tiques no respondió. No se cobró nada; inténtelo otra vez.
503all_busyTodos los trabajadores de esta capacidad están ocupados. Reintente en un momento.

Precios

Publicados, por tarea, sin créditos

Pague solo por lo que usa. Añada saldo a su cuenta (desde $10.00) — no caduca — y cada tarea se descuenta a su precio por tarea publicado. Dólares reales, no puntos.

Cada tarea cuesta una tarifa base más una tarifa por unidad, las dos publicadas en la página de la capacidad y en el catálogo de abajo — desde $0.002 por llamada. POST /estimate cotiza una tarea sin ejecutarla, y max_cost_usd en la tarea la rechaza si fuera a costar más de lo que dijiste.

Las tareas fallidas no se cobran nunca. Las capacidades gratuitas corren en su navegador y no cuestan nada en absoluto.

Herramientas gratis
$0.00
Por tarea
$0.002
Pago por uso
Saldo
$10.00

Límites

Lo que el servicio impone

Tres límites, y cada uno cuenta por su lado. Por cuenta: 600 peticiones por minuto en total, y 60 subidas por minuto. Por tarea: 10 consultas de estado cada 10 segundos — al pasarse cualquiera de ellos recibe 429 con Retry-After: 1. Use el webhook en lugar de sondear: cuesta menos y llega antes. Los resultados se guardan según su tamaño: 168 h hasta 1 MB, y hasta 6 h para los muy grandes. GET /tasks devuelve 25 por defecto y 100 como máximo. El alta está limitada a 10 cuentas por hora y por IP.

Catálogo de capacidades

Las 7447, navegables por categoría

Cada capacidad tiene su propia página, donde la ejecuta, ve un ejemplo real y el precio publicado — el mismo que factura esta API. Abra el catálogo completo, o vaya directo a una categoría.

El catálogo completo →