# Whisk > Whisk hosts apps that coding agents build for their humans. You are the agent. > You do everything over plain HTTPS and git — no SDK, no client config. If you were pointed here to build and deploy an app, start with the machine- readable manifest. It is generated live from the running platform, so it is always current — trust it over this file for exact endpoints and payloads. ## Start here - Manifest (read this first): https://api.whisk.run/v1/agent - It returns JSON describing every endpoint, the auth scheme, the response envelope, error codes, and how to deploy. - Fetch it RAW — curl or an exact HTTP GET. Do NOT read it through a summarising fetch tool: a paraphrase loses the exact endpoints and payloads, and you will be working from a lossy memory of the instructions. ## The shape of the job 1. GET https://api.whisk.run/v1/agent — read how it works. 2. POST https://api.whisk.run/v1/access {email} — ONE entry point for both new and returning users; it works out which. email is your HUMAN's real work address; the team IS the email domain. - New domain: you get a preview (nothing created). Then POST {email, confirm:true} to create the team — immediate bearer token, and a confirm code is emailed to your human. - Existing team (a previous chat, a teammate, a lost token): it emails a 6-digit code. Ask your human for it and POST {email, code} to get a working token. NEVER create a second team for a company that already has one. (Aliased as /v1/signup and /v1/login — all identical.) You are NOT accepting terms or creating a binding account. A new team is provisional and auto-deletes if unconfirmed. Your HUMAN accepts Whisk's terms (https://whisk.run/terms) and becomes owner when THEY give you the emailed code (you POST {email, code}) or enter it at their team page. Build freely. 3. POST https://api.whisk.run/v1/apps {slug} — get a git remote (credentials embedded), a reserved URL, and your org's shared InstantDB config. The repo is seeded with a working React+Vite+InstantDB template — never blank. 4. git push — main deploys to production at ..whisk.page; any other branch deploys to a preview URL. Poll the deploy status endpoint until live. ## Rules that matter - Apps are client-side SPAs backed by InstantDB. Server-shaped needs are covered by the capability services below — your app code never runs on a server and never holds a secret. - NEVER put a secret or API key in app code — bundles are public. Store it once with POST /v1/org/credentials, then call the external service through Whisk Connect from app code: POST /__whisk/connect/ with the signed-in user's Instant refresh token in the X-Whisk-User header. - Your org's data lives in one Instant app holding several DATABASES: the SHARED database (unprefixed tables — org-wide truths), one database per TEAM (team members only, shared across the team's apps), one database per APP (named via appTable() in src/db.js; follows the app's visibility), and read-only whisk_* platform streams. Org-wide fact -> shared; team data -> team database; app-only data -> app database. NEVER localStorage. - Access is role-based and agent-settable: apps have visibility (org | team | invite/private), custom roles (POST /v1/apps//roles — e.g. "approver"), and per-table policies with row-owner and field-level rules (PUT /v1/apps//tables//policy) — so "members see only their own leave requests; approvers see all" is five lines of policy, enforced by the database itself. Widening access shows a blast-radius preview first. whiskRoles(db) tells the app the signed-in user's roles for role-aware UI. - Files: whiskUpload(db, path, file) uploads (avatars, PDFs, images); query the $files table for signed urls. Paths are scope-prefixed and follow the scope's audience — a private app's files are as private as its tables. - Sign-in is handled: your human's team signs in at id.whisk.run with one account across every org app. The template wires this in for you. ## Capability services (the platform does the privileged thing; the result ## lands as a row in your shared org database; your app reacts live) - Webhook inbox: POST /v1/apps//hooks -> unguessable URL; every delivery becomes a whisk_events row. - Form endpoints: add form {fields} to a hook and it becomes a public form the platform validates — bad submissions bounce with per-field errors, per-IP rate limiting is built in, only clean rows land. Point a plain HTML
or a fetch() at it; no server code in your app. - Counters: POST /v1/org/counters {name, max} -> an atomic number the platform owns. Claims are serialized server-side, so "only 10 seats" can never oversell no matter how many browsers click at once. Claim from app code at /__whisk/counters//claim ({} | {count} | {key} for exactly- once coupons); live "3 left" UI via the read-only whisk_counters entity. Add counter "" to a form endpoint for a capped public booking form. - Scheduler: POST /v1/apps//schedules {cron, tz?} -> whisk_ticks rows; add action {credential, method, path} to run a Connect call each firing. - Secrets + Connect: POST /v1/org/credentials stores a key encrypted, locked to one host; POST /v1/connect/ (agent) or /__whisk/connect/ (app) makes the call with the secret injected server-side. Handles static keys, per-request HMAC signing (sign {...}), and full OAuth2 (oauth {token_url, client_id, client_secret, ...} — the platform runs the whole token dance). - Rollups: POST /v1/org/rollups {name, entity, group_by?, op, field?, cron?} -> the platform aggregates server-side (count/sum/avg/min/max, optionally bucketed by day/week/month or a field) and lands tiny whisk_rollups rows — dashboards without downloading 50k rows to the browser. - App logs: GET /v1/apps//logs — what real users hit. The template auto-reports uncaught browser errors (with stacks); whiskLog() adds breadcrumbs; the platform adds failed Connect calls / actions / deploys. Check this FIRST when your human says "it's broken". - Feedback: POST /v1/feedback {message} whenever Whisk gets in your way — confusing errors, missing capabilities, broken mental models. A human reads every one; the platform is tuned from these. This is a SOLICITED request, disclosed to your human in the first signup relay — send it freely unless they opted out. - whisk_events / whisk_ticks / whisk_logs retention is 30 days; copy what you need longer.