Tutto quello che fa il KIT, in un posto solo
ForHosting KIT è un catalogo di 7447 attività pronte all’uso — converti un documento, leggi una fattura, trascrivi un audio, verifichi un IBAN, generi un codice QR — in 14 categorie. Le esegui qui dal browser, oppure le chiami dal tuo codice con un solo POST autenticato. Questa pagina è il riferimento API completo: endpoint, modello asincrono, contratto dei webhook, errori e prezzi.
Cos’è il KIT
Un catalogo di attività, non un modello
Ogni strumento è un’attività: mandi un input, ricevi un risultato. Niente token, niente finestre di contesto, niente prompt da ingegnerizzare. Un’attività ha un prezzo pubblicato, un’unità documentata e una forma fissa.
Quattro modi per eseguirne una. Web — ogni strumento ha la sua pagina e gira nel browser; quelli gratis non escono mai dal tuo dispositivo. API — un solo POST autenticato, documentato qui sotto. Email e Telegram — mandi l’attività a un indirizzo del KIT. L’API è un canale, non il prodotto.
Per iniziare
Da zero a un risultato in tre chiamate
Crei un account, ricevi la chiave, esegui un’attività. Niente telefonate commerciali, niente lista d’attesa.
Ottieni una chiave API
POST /signup con la tua email restituisce una chiave che inizia con kit_live_. La vedi una volta sola. Ne conserviamo solo l’hash SHA-256, quindi se la perdi non possiamo recuperarla — te ne emettiamo una nuova.
Scegli uno strumento
GET /catalog elenca tutti e 7447 gli strumenti, con prezzo e unità aggiornati. Oppure sfoglia il catalogo in fondo a questa pagina.
Eseguila
Fai POST sull’endpoint dello strumento. Ricevi subito un task_id e il risultato arriva al tuo webhook.
Autenticazione
Bearer token, mostrato una volta sola
Ogni richiesta all’API porta Authorization: Bearer kit_live_…. Dopo il prefisso, le chiavi sono 48 caratteri esadecimali.
Di ogni chiave conserviamo solo l’hash SHA-256. È una scelta voluta: un dump del database non consegna a nessuno le tue credenziali — ma vuol dire anche che davvero non possiamo rispedirti la chiave via email. L’hai persa? La revochiamo e ne emettiamo una nuova.
Una chiave sbagliata restituisce sempre 401 e non dice mai perché. Revocata, digitata male o mai esistita sono indistinguibili apposta: dirti quale delle tre era vuol dire dirlo anche a chi attacca.
Il modello asincrono
Ogni attività è asincrona. Senza eccezioni.
Fai POST dell’attività
Ricevi 202 con un task_id e stato queued, più quanto costerà. I soldi vengono bloccati, non addebitati.
Gira sull’edge
Sotto il secondo per le attività di calcolo; qualche secondo per IA e media.
Il risultato ti trova
Lo mandiamo in POST al tuo webhook_url, se ne hai indicato uno. Altrimenti GET /tasks/{id}/result. I risultati restano in base alla dimensione: da 168 h per quelli piccoli (fino a 1 MB) a 6 h per i più grandi.
Se fallisce non paghi
L’attività viene tentata fino a 3 volte in tutto, con backoff fra un tentativo e l’altro. Se fallisce comunque, il blocco viene rilasciato e non ti addebitiamo nulla. Mai.
Riferimento API
Tutti gli endpoint a cui il KIT risponde
Le rotte non hanno prefisso di versione. /v1/* continua a rispondere per i client vecchi, ma non è la forma canonica e il codice nuovo non dovrebbe usarla.
URL di base: https://api.kit.forhosting.com
| Metodo | Rotta | Auth | Cosa fa |
|---|---|---|---|
ANY |
/ |
Pubblico | Indice del servizio: versione, numero di capacità e l’elenco di endpoint che l’API annuncia di sé. Senza chiave, e risponde a qualsiasi metodo. |
POST |
/{alias} |
Chiave API | Scorciatoia per capacità di POST /tasks con il type fisso — per esempio POST /ocr/invoice. È la forma che mostra ogni pagina di capacità. |
GET |
/account |
Chiave API | Saldo del conto: available_usd è il saldo reale del portafoglio, più held_usd. Quando il portafoglio è gestito dall’area cliente, balance.source vale "portal" e balance_endpoint punta al valore aggiornato. |
POST |
/agent/ask |
Chiave API In arrivo | Non implementato — restituisce 501 con la chiave e 401 senza. L’assistente conversazionale si sta costruendo altrove; per trovare una capacità usa POST /catalog/search. |
GET |
/catalog |
Pubblico | Tutte le capacità con prezzo e unità aggiornati. ?lang=en|es, ?q= per filtrare, ?limit=, ?schema=1 per lo schema di input e ?channel= per avere il prezzo già adeguato a quel canale — chiedi il canale su cui fatturerai, altrimenti mostri una cifra e ne addebiti un’altra. |
POST |
/catalog/search |
Pubblico | {query} → le capacità che corrispondono, ognuna con il prezzo già scritto. Senza chiave. Assegna il punteggio per copertura di parola intera con una soglia, quindi una domanda che non capisce non restituisce nulla invece di tirare a indovinare — è voluto. |
POST |
/estimate |
Chiave API | {type, input} → unità, prezzo e dettaglio. Preventiva senza eseguire. Quando la quantità reale non si può sapere prima (le pagine di un PDF dietro a una URL), la risposta lo dice con estimated: true. |
GET |
/mobile/bootstrap |
Pubblico | Quello che serve all’app per partire: categorie, etichette e gli stessi prezzi adeguati al canale. Senza chiave. Nemmeno questa fa parte del contratto pubblico, per lo stesso motivo. |
GET |
/mobile/catalog |
Pubblico | Proiezione del catalogo per l’app, con i prezzi già adeguati al canale dell’app. Senza chiave. Non fa parte del contratto pubblico: la sua forma segue l’app e può cambiare senza preavviso — sviluppa contro GET /catalog. |
GET |
/plans |
Pubblico | Importi di ricarica: currency e topup (sku, default_amount, min_amount). Nient’altro — non ci sono piani da sottoscrivere. |
POST |
/signup |
Pubblico | {email} → 201 con la tua api_key, mostrata una volta sola. 409 se l’email esiste già; 429 oltre 10/h per IP. |
GET |
/tasks |
Chiave API | Le tue attività. ?status=, ?limit= (25 di default, 100 al massimo). |
POST |
/tasks |
Chiave API | {type, input, webhook_url?, max_cost_usd?} → 202. Paghi l’unità reale dell’attività — pagine, minuti, immagini — misurata durante l’esecuzione, non la stima iniziale. max_cost_usd è un tetto rigido: se il costo reale lo supera, l’attività fallisce e non ti viene addebitato nulla. Manda Idempotency-Key perché riprovare sia sicuro: una ripetizione restituisce l’attività originale con idempotent: true. |
DELETE |
/tasks/{id} |
Chiave API | Annulla un’attività in coda e libera la sua riserva. |
GET |
/tasks/{id} |
Chiave API | Stato dell’attività. 10 letture ogni 10 secondi per attività; oltre, 429 con Retry-After: 1. Meglio il webhook. |
GET |
/tasks/{id}/events |
Chiave API In arrivo | Non implementato — restituisce 501. L’SSE arriverà; usa il webhook. |
GET |
/tasks/{id}/result |
Chiave API | Risultato JSON, o il file come allegato. 409 non pronto, 410 scaduto, 422 fallito. La conservazione dipende dalla dimensione del risultato: 168 h per quelli piccoli, fino a 6 h per quelli molto grandi. |
POST |
/tasks/{id}/retry |
Chiave API | Rimette in coda un’attività fallita. |
POST |
/uploads |
Chiave API | Manda un file locale: corpo binario grezzo, con il Content-Type del file. → 201 con ref: "kit://upl_…", che poi metti dove andrebbe una URL: {"input": {"pdf": "kit://upl_…"}}. Un caricamento può alimentare più attività. I ref vivono 24 h. Massimo 100 MiB (104.9 MB) per caricamento; ogni capacità applica in più il proprio limite. |
Webhook
Consegna firmata, e come verificarla
Imposti webhook_url quando crei l’attività e noi mandiamo lì il risultato in POST appena è pronto. È la strada consigliata: costa meno del polling e arriva prima.
Verifica la firma prima di fidarti del corpo. Ogni consegna porta KIT-Signature: v1=<hex> e KIT-Timestamp: <secondi unix>. La firma è HMAC-SHA256 sulla stringa <timestamp>.<corpo grezzo> — il timestamp e il punto fanno parte del payload firmato, non sono decorazione. Firma i byte grezzi che hai ricevuto, non un oggetto riserializzato.
La consegna viene tentata fino a 5 volte con backoff esponenziale. Un 4xx dal tuo endpoint ferma subito i tentativi — lo leggiamo come “il tuo handler è sbagliato”, non “riprova più tardi”. Ritentiamo solo su 5xx ed errori di rete. Dopodiché la consegna finisce in dead letter.
Cosa mandiamo in 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
}
}Verificare la firma
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)Errori
HTTP standard, slug leggibile dalla macchina
Ogni errore porta nel corpo uno slug error stabile. Fai il match sullo slug, non sul messaggio: i messaggi sono localizzati e possono cambiare.
| HTTP | Errore | Significato |
|---|---|---|
400 | flow_depth | Una capacità composta si è annidata più a fondo del consentito. Appiattisci i passi. |
400 | invalid_amount | L’importo manca, non è un numero, oppure è fuori dall’intervallo consentito. |
400 | invalid_email | L’email manca o non è valida. |
400 | invalid_input | All’input manca un campo obbligatorio o non ha la forma che questa attività si aspetta. |
400 | invalid_json | Il corpo della richiesta non è un JSON valido. |
400 | missing_type | Manca il campo 'type' nella richiesta. Consulta GET /catalog. |
400 | unknown_op | Operazione sconosciuta per questa capacità. Controlla il nome nel catalogo. |
400 | unsafe_url | La URL punta a un posto da cui non scaricheremo: un indirizzo interno o non pubblico. |
401 | auth_required | Questo passo richiede un account identificato e la richiesta non ne porta nessuno. |
401 | no_key | La richiesta non porta una API key, o l’account non ne ha nessuna attiva. |
401 | unauthorized | Chiave API mancante o non valida: controlla l'header Authorization. |
402 | account_suspended | Il tuo account è sospeso, di solito per il tetto di spesa. Scrivici per riattivarlo. |
402 | insufficient_balance | Credito esaurito: ricarica per continuare a eseguire attività. |
402 | max_cost_exceeded | L’attività è costata più del max_cost_usd che hai impostato. Non è stato addebitato nulla. |
403 | forbidden | La credenziale è valida ma non è autorizzata a farlo. |
404 | input_not_found | Questo riferimento kit:// non esiste. Ricarica il file con POST /uploads. |
404 | not_found | Nessuna attività o risorsa a quel percorso. |
404 | unknown_type | Tipo di attività sconosciuto: controlla il campo type della richiesta. |
409 | alias_taken | Quell’alias di posta in entrata è di qualcun altro. Scegline un altro. |
409 | already_accepted | Quell’accettazione è già stata usata. Ognuna vale esattamente una volta. |
409 | email_taken | Esiste già un account con questa email. |
409 | need_lease | Un altro worker sta già eseguendo questa attività. Aspetta che finisca. |
409 | not_cancellable | L’attività non è più in coda, quindi non si può annullare. Solo quelle in coda si annullano. |
409 | not_ready | L’attività non è ancora finita: controlla lo stato o aspetta il webhook. |
409 | not_retryable | Si riprovano solo le attività fallite. Questa è in un altro stato. |
410 | expired | La finestra di conservazione del risultato è passata e non è più disponibile. |
410 | input_expired | Questo riferimento kit:// è scaduto. I caricamenti durano 24 h; ricarica il file. |
410 | quote_expired | Il preventivo ha superato la sua finestra di validità. Chiedine uno nuovo. |
413 | input_too_large | Il file o il testo inviato supera il limite di questo strumento. |
413 | resolution_too_high | L’immagine o il video superano la risoluzione che questa capacità accetta. |
422 | conversion_failed | Non è stato possibile convertire il file. Di solito è un formato corrotto o inatteso. |
422 | engine_error | Il motore ha fallito a ogni tentativo. La riserva è stata liberata: non ti addebitiamo nulla. |
422 | needs_rework | Il risultato non ha passato il proprio controllo di qualità, quindi non viene consegnato. Non addebitato. |
429 | rate_limited | Troppe richieste in poco tempo: rallenta e riprova tra qualche secondo. |
500 | lease_error | Non è stato possibile prendere in carico l’attività. Torna in coda. |
500 | ledger_error | Non è stato possibile bloccare né liquidare il credito. Riprova. |
500 | no_hold | L’attività non ha una riserva da liquidare. Non dovrebbe succedere; se succede, faccelo sapere. |
500 | no_result | L’attività è terminata senza produrre un risultato. |
501 | coming_soon | Questo strumento non è ancora attivo via API: arriva presto. |
501 | mail_not_configured | Questa capacità manda email e l’account non ha ancora un mittente configurato. |
501 | not_implemented | Questo endpoint o questa capacità non è ancora disponibile. |
501 | tickets_not_configured | L’integrazione dei ticket non è configurata per questo account. |
501 | unsupported | Questa operazione non è ancora supportata (per esempio, i flow non si possono preventivare). |
502 | model_output_invalid | Il modello ha restituito qualcosa che non corrisponde all’output dichiarato. Non addebitato. |
502 | tickets_unreachable | Il sistema di ticket non ha risposto. Non è stato addebitato nulla; riprova. |
503 | all_busy | Tutti i worker di questa capacità sono occupati. Riprova tra poco. |
Prezzi
Pubblicati, per attività, senza crediti
Si paga solo ciò che si utilizza. Si aggiunge saldo al proprio account (a partire da $10.00) — non scade mai — e ogni attività vi attinge al proprio prezzo pubblicato. Dollari veri, non punti.
Ogni attività costa una tariffa base più una tariffa per unità, entrambe pubblicate sulla pagina dello strumento e nel catalogo qui sotto — da $0.002 a chiamata. POST /estimate ti dà il preventivo di un’attività senza eseguirla, e max_cost_usd sull’attività la rifiuta se costasse più di quanto hai detto.
Le attività fallite non si pagano mai. Gli strumenti gratis girano nel tuo browser e non costano proprio nulla.
Limiti
Cosa impone il servizio
Tre limiti, e ognuno conta per conto suo. Per account: 600 richieste al minuto in tutto e 60 caricamenti al minuto. Per attività: 10 letture di stato ogni 10 secondi — superato uno qualsiasi, ricevi 429 con Retry-After: 1. Usa il webhook invece del polling: costa meno e arriva prima. I risultati restano in base alla dimensione: 168 h fino a 1 MB e 6 h per quelli molto grandi. GET /tasks restituisce 25 elementi di default, 100 al massimo. La registrazione è limitata a 10 account l’ora per IP.
Catalogo degli strumenti
Tutti e 7447, sfogliabili per categoria
Ogni strumento ha la sua pagina, dove lo esegui, vedi un esempio vero e il prezzo pubblicato — lo stesso che fattura questa API. Apri il catalogo completo, oppure vai dritto a una categoria.
Nessuna garanzia
Quello che non promettiamo
Il KIT è fornito “così com’è”: nessuna garanzia, nessun impegno di uptime, nessuno SLA (l’infrastruttura dedicata con SLA è un extra a pagamento) e nessun supporto garantito. La clausola completa sul KIT è nei Termini.