ForHosting KIT

Everything the KIT does, in one place

ForHosting KIT is a catalog of 7447 ready-made tasks — convert a document, read an invoice, transcribe audio, validate an IBAN, generate a QR — across 14 categories. Run them here on the web, or call them from your code with one authenticated POST. This page is the complete API reference: endpoints, the async model, the webhook contract, errors and pricing.

Use it from WebAPIEmailTelegramApp soon

What the KIT is

A task catalog, not a model

Every capability is a task: you send input, you get a result. There are no tokens, no context windows and no prompt engineering. A task has a published price, a documented unit and a fixed shape.

Four ways to run one. Web — every capability has its own page and runs in the browser; the free ones never leave your device. API — one authenticated POST, documented below. Email and Telegram — send the task to a KIT address. The API is one channel, not the product.

Quickstart

From nothing to a result in three calls

Create an account, get your key, run a task. No sales call, no waiting list.

1

Get an API key

POST /signup with your email returns a key that starts with kit_live_. It is shown once. We store only its SHA-256 hash, so if you lose it we cannot recover it — we issue a new one.

2

Pick a capability

GET /catalog lists all 7447 with their live price and unit. Or browse the catalog at the bottom of this page.

3

Run it

POST to the capability's endpoint. You get a task_id back immediately and the result arrives at your webhook.

Authentication

Bearer token, shown once

Every API request carries Authorization: Bearer kit_live_…. Keys are 48 hex characters after the prefix.

We store only the SHA-256 hash of your key. That is deliberate: a database dump does not hand anyone your credentials — but it also means we genuinely cannot email you your key back. Lost it? We revoke and issue.

A bad key always returns 401 and never says why. Revoked, mistyped and never-existed are indistinguishable on purpose: telling you which one it was is telling an attacker too.

The async model

Every task is asynchronous. No exceptions.

1

You POST the task

Returns 202 with a task_id and status queued, plus what it will cost. The money is held, not charged.

2

It runs on the edge

Sub-second for compute tasks; seconds for AI and media.

3

The result finds you

It is POSTed to your webhook_url if you gave one. Otherwise GET /tasks/{id}/result. Results are kept by size — from 168 h for small ones (up to 1 MB) down to 6 h for the largest.

4

Failure costs nothing

A task is attempted up to 3 times in total, with backoff between attempts. If it still fails, the hold is released and you are not charged. Ever.

API reference

Every endpoint the KIT answers

Routes carry no version prefix. /v1/* still resolves for older clients, but it is not the canonical form and new code should not use it.

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

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

MethodRouteAuthWhat it does
ANY / Public Service index: version, capability count and the endpoint list the API announces about itself. No key, and it answers any method.
POST /{alias} API key Per-capability shortcut for POST /tasks with type fixed — e.g. POST /ocr/invoice. This is the form each capability page shows.
GET /account API key Account balance: available_usd is your real wallet balance, plus held_usd. When the wallet is managed by the client area, balance.source is "portal" and balance_endpoint points to the live figure.
POST /agent/ask API key Soon Not implemented — returns 501 with a key, 401 without one. The conversational assistant is being built elsewhere; use POST /catalog/search to find a capability.
GET /catalog Public All capabilities with live price and unit. ?lang=en|es, ?q= to filter, ?limit=, ?schema=1 for the input schema, and ?channel= to get the price already adjusted for that channel — ask for the channel you will bill on, or you will show one figure and charge another.
POST /catalog/search Public {query} → the capabilities that match, each with its price already written out. No key. It scores by whole-word coverage with a threshold, so a query it doesn't understand returns nothing instead of guessing — that is deliberate.
POST /estimate API key {type, input} → units, price and breakdown. Quotes without running. When the real quantity can't be known upfront (the page count of a PDF behind a URL), the reply says estimated: true.
GET /mobile/bootstrap Public What the mobile app needs to start: categories, labels and the same channel-adjusted prices. No key. Not part of the public contract either — same reason as above.
GET /mobile/catalog Public Catalogue projection for the mobile app, with prices already adjusted for the app channel. No key. It is not part of the public contract: its shape follows the app and can change without notice — build against GET /catalog.
GET /plans Public Top-up amounts: currency and topup (sku, default_amount, min_amount). Nothing else — there are no plans to subscribe to.
POST /signup Public {email}201 with your api_key, shown once. 409 if the email exists; 429 over 10/h per IP.
GET /tasks API key Your tasks. ?status=, ?limit= (25 default, 100 max).
POST /tasks API key {type, input, webhook_url?, max_cost_usd?}202. You are billed for the task's real unit — pages, minutes, images — measured while it runs, not for the upfront estimate. max_cost_usd is a hard ceiling: if the real cost exceeds it the task fails and nothing is charged. Send Idempotency-Key to make retries safe: a replay returns the original task with idempotent: true.
DELETE /tasks/{id} API key Cancel a queued task and release its hold.
GET /tasks/{id} API key Task status. 10 reads every 10 seconds per task; over that, 429 with Retry-After: 1. Prefer the webhook.
GET /tasks/{id}/events API key Soon Not implemented — returns 501. SSE is coming; use the webhook.
GET /tasks/{id}/result API key JSON result, or the file as an attachment. 409 not ready, 410 expired, 422 failed. Retention depends on result size: 168 h for small results, down to 6 h for very large ones.
POST /tasks/{id}/retry API key Re-queue a failed task.
POST /uploads API key Send a local file: raw binary body, Content-Type of the file. → 201 with ref: "kit://upl_…", which you then put wherever a URL would go: {"input": {"pdf": "kit://upl_…"}}. One upload can feed several tasks. Refs live 24 h. Max 100 MiB (104.9 MB) per upload; each capability applies its own limit on top.

Webhooks

Signed delivery, and how to verify it

Set webhook_url when you create a task and we POST the result there when it is ready. This is the recommended path: it costs less than polling and arrives sooner.

Verify the signature before you trust the body. Every delivery carries KIT-Signature: v1=<hex> and KIT-Timestamp: <unix seconds>. The signature is HMAC-SHA256 over the string <timestamp>.<raw body> — the timestamp and the dot are part of the signed payload, not decoration. Sign the raw bytes you received, not a re-serialized object.

Delivery is attempted up to 5 times with exponential backoff. A 4xx from your endpoint stops retrying immediately — we read it as “your handler is wrong”, not “try later”. Only 5xx and network errors retry. After that the delivery is dead-lettered.

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

Errors

Standard HTTP, machine-readable slug

Every error carries a stable error slug in the body. Match on the slug, not the message: messages are localized and may change.

HTTPErrorMeaning
400flow_depthA composed capability nested deeper than allowed. Flatten the steps.
400invalid_amountThe amount is missing, not a number, or outside the allowed range.
400invalid_emailThe email address is missing or malformed.
400invalid_inputThe input is missing a required field or isn't the shape this task expects.
400invalid_jsonThe request body isn't valid JSON.
400missing_typeNo 'type' field on the request. See GET /catalog.
400unknown_opUnknown operation for this capability. Check the operation name against the catalogue.
400unsafe_urlThe URL points somewhere we will not fetch from — an internal or non-public address.
401auth_requiredThis step needs an identified account and the request has none.
401no_keyNo API key on the request, or the account has none active.
401unauthorizedMissing or invalid API key.
402account_suspendedYour account is suspended — usually the per-account spend cap. Contact us to lift it.
402insufficient_balanceYour balance doesn't cover the task price.
402max_cost_exceededThe task cost more than the max_cost_usd you set. Nothing was charged.
403forbiddenThe credential is valid but not allowed to do this.
404input_not_foundThat kit:// reference does not exist. Upload the file again with POST /uploads.
404not_foundNo task or resource at that path.
404unknown_typeThat task type doesn't exist.
409alias_takenThat inbound email alias belongs to someone else. Pick another.
409already_acceptedThat acceptance was already used. Each one works exactly once.
409email_takenAn account already exists with that email.
409need_leaseAnother worker is already running this task. Wait for it to finish.
409not_cancellableThe task is no longer queued, so it cannot be cancelled. Only queued tasks can.
409not_readyThe task isn't finished yet. Poll its status or wait for the webhook.
409not_retryableOnly failed tasks can be retried. This one is in another state.
410expiredThe result's retention window has passed and it is no longer stored.
410input_expiredThat kit:// reference has expired. Uploads live 24 h; upload the file again.
410quote_expiredThe quote is older than its validity window. Ask for a new one.
413input_too_largeThe file exceeds the size limit.
413resolution_too_highThe image or video exceeds the resolution this capability accepts.
422conversion_failedThe file could not be converted. It is usually a corrupt or unexpected format.
422engine_errorThe engine failed after every attempt. The hold was released — you are not charged.
422needs_reworkThe result did not pass its own quality check, so it is not delivered. Not charged.
429rate_limitedToo many requests. Use the webhook instead of polling.
500lease_errorThe task could not be leased for execution. It goes back to the queue.
500ledger_errorThe balance couldn't be held or settled. Try again.
500no_holdThe task has no reservation to settle. It should not happen; if it does, tell us.
500no_resultThe task finished but produced no result.
501coming_soonCapability being deployed (Phase 1b). Its page exists; it doesn't accept executions yet.
501mail_not_configuredThis capability sends email and the account has no sender configured yet.
501not_implementedThis endpoint or capability isn't available yet.
501tickets_not_configuredThe ticket integration is not set up for this account.
501unsupportedThis operation isn't supported yet (for example, flows can't be quoted).
502model_output_invalidThe model returned something that does not match the declared output. Not charged.
502tickets_unreachableThe ticket system did not answer. Nothing was charged; try again.
503all_busyEvery worker for this capability is busy. Retry shortly.

Pricing

Published, per task, no credits

Pay only for what you use. Add balance to your account (from $10.00) — it never expires — and every task draws from it at its published per-task price. Real dollars, not points.

Each task costs a base rate plus a unit rate, both published on the capability's own page and in the catalog below — from $0.002 per call. POST /estimate quotes a task without running it, and max_cost_usd on a task refuses it if it would cost more than you said.

Failed tasks are never charged. Free capabilities run in your browser and cost nothing at all.

Free tools
$0.00
Per task
$0.002
Pay-as-you-go
Balance
$10.00

Limits

What the service enforces

Three limits, and they are keyed differently. Per account: 600 requests a minute overall, and 60 uploads a minute. Per task: 10 status reads every 10 seconds — over any of them you get 429 with Retry-After: 1. Use the webhook instead of polling: it costs less and arrives sooner. Results are kept by size: 168 h for results up to 1 MB, down to 6 h for very large ones. GET /tasks returns 25 by default, 100 maximum. Signup is limited to 10 accounts per hour per IP.

Capability catalog

All 7447, browsable by category

Every capability has its own page, where you can run it, see a real example and the published price — the same price this API bills. Open the full catalogue, or jump straight to a category.

The full catalog →