# Interfold — Full Documentation > The complete Interfold documentation, concatenated. Individual pages > are also available as raw Markdown at https://docs.interfold.site/raw/ > and indexed at https://docs.interfold.site/llms.txt --- # Getting started Interfold lets you and your agents publish real websites, files, and backend functions from the command line — no build step, no servers to manage. Ship a page, expose an API endpoint, persist data, and get a live `*.interfold.site` URL in seconds. This guide takes you from zero to a live page and a working function. - New to the model? Read [Core concepts](/concepts) first. - Building an agent that uses Interfold? Jump to the [Agent guide](/agents). --- ## 1. Install the CLI The `interfold` CLI is the primary way to work with Interfold. Install it with: ```sh curl -fsSL https://downloads.interfold.dev/install.sh | bash ``` The installer adds Interfold to your zsh or Bash startup files when it recognizes your shell. Open a new terminal window, or run the `source` command it prints, then continue below. To manage your PATH yourself, run the installer with `bash -s -- --no-path`. Verify the install: ```sh interfold version ``` ## 2. Log in Authenticate the CLI. This opens a browser to approve the session and stores a credential locally (at `~/.interfold/credentials.json`) — you never paste keys into your shell. ```sh interfold login ``` Confirm you're authenticated: ```sh interfold whoami ``` You'll see the account the CLI is acting as. Everything you publish belongs to this account. ## 3. Create a site A **site** is a container for files and functions, served at its own `*.interfold.site` subdomain. Create one: ```sh interfold sites create --name "My Site" --access PUBLIC ``` The response includes the site `id` and `subdomain`. Save the id — site-scoped commands require a `--site ` flag. > `--access PUBLIC` means anonymous visitors can open the site. Use `PRIVATE` > for a draft or team-only project. See [Sites & access](/sites). ## 4. Publish a page Create a local HTML file: ```sh cat > index.html <<'HTML' Hello, Interfold

Hello from Interfold

HTML ``` Upload it to the site's web directory: ```sh interfold files put ./index.html /web/index.html --site --content-type 'text/html; charset=utf-8' ``` Look up your subdomain and open the live URL: ```sh interfold sites get curl -I https://.interfold.site/ ``` Your page is live at `https://.interfold.site/`. ## 5. Deploy a function Interfold Functions let you run TypeScript on the server at `/api/*`. Create a handler: ```sh cat > hello.ts <<'TS' export async function handler(req: Request, ctx: InterfoldContext) { const name = new URL(req.url).searchParams.get('name') ?? 'world' return Response.json({ ok: true, message: `hello ${name}` }) } TS ``` Deploy it by uploading the source under `/api/`: ```sh interfold files put ./hello.ts /api/hello.ts --content-type text/typescript ``` Invoke it: ```sh curl -i "https://.interfold.site/api/hello?name=agent" ``` You now have a live page and a live endpoint. See [Functions](/functions) for the full runtime contract, [Databases](/databases) or [Data files](/data-storage) for persistence, and [Secrets](/secrets) for runtime config. --- ## Where to go next - [Core concepts](/concepts) — the mental model behind sites, files, access, and functions. - [Cron Jobs](/cron-jobs) — scheduled TypeScript for recurring work. - [CLI reference](/cli) — every command and flag. - [API reference](/api-reference) — the REST API behind the CLI. - [Agent guide](/agents) — how to drive Interfold from a coding agent. --- # Core concepts Interfold has a small, consistent model. Once these ideas click, the CLI and API read like plain English. ## Accounts An **account** is the workspace and billing boundary. Every site, file, function, cron job, and secret belongs to exactly one account. Users join accounts through membership; API keys are scoped to a single account with Read-only or Read/write access. Read/write includes all reads. See [API authentication](/api-reference). ```sh interfold accounts list interfold accounts current ``` ## Buckets A **bucket** is an account-owned collection of files. It works without hosting: store documents, source, assets, and data through the bucket Files API. A Site can attach to a bucket; creating a Site without a bucket creates one automatically. ## Sites A **site** attaches hosting and runtime behavior to one bucket, served at its own subdomain, `https://.interfold.site`. A Site interprets fixed bucket directories and owns its runtime resources: | Resource | Path convention | Purpose | | ---------- | --------------- | ----------------------------------------------- | | Web files | `/web/*` | Verbatim HTML, CSS, JS, images, and text | | Functions | `/api/*.ts` | Server-side TypeScript endpoints | | Cron Jobs | `/cron/*.ts` | Scheduled TypeScript handlers | | Data files | `/data/*` | File storage for functions and cron jobs | | Database | — | Structured SQL data for functions and cron jobs | A site has an `access` setting (`PUBLIC` or `PRIVATE`) that controls who can reach its static output. See [Sites & access](/sites). ## Files Everything you publish is a **file** at a path. `interfold files put` creates or replaces a file; the path determines how it behaves: - `/web/index.html`, `/web/style.css`, `/web/logo.png` — **web files**, served at `/`, `/style.css`, and `/logo.png`. - `/api/hello.ts` — a **function source**, deployed as an endpoint. - `/cron/refresh.ts` — a **cron source**, deployed as a scheduled handler. - `/data/state.json` — **data**, written by handlers, never served publicly. The path is the source of truth. Files under `/web/` are served verbatim with the prefix omitted from hosted URLs. There is no runtime Markdown rendering or other transformation, and uploading is publishing. Because the prefix is omitted, `/web/api/`, `/web/cron/`, `/web/data/`, and `/web/_interfold/` are rejected rather than colliding with reserved hosted routes. ## Access Bucket API access always requires account authentication. A Site's `PUBLIC` or `PRIVATE` setting controls anonymous access only to hosted `/web/` files. A deployed `/api/` runtime is anonymously callable for either Site setting; the handler must enforce any function-specific authorization. There are no per-file overrides. Source, cron, data, database and migration assets, and files outside `/web/` are never served directly; a function can still return data deliberately. See [Sites & access](/sites). ## Functions A **function** is a single TypeScript file at `/api/.ts` that exports a `handler`. It runs on request and returns a standard `Response`. Functions get a `ctx` object with access to persistent data and site secrets. ```ts export async function handler(req: Request, ctx: InterfoldContext) { return Response.json({ ok: true, siteId: ctx.siteId }) } ``` See [Functions](/functions). ## Cron Jobs A **cron job** is a TypeScript file at `/cron/.ts` with a static UTC schedule and a named `handler`. It runs in the same isolated environment as a function, with access to site data and secrets but no browser request or user session. See [Cron Jobs](/cron-jobs). ## Storage & secrets - **Databases** (`ctx.db`) store structured application data and support SQL queries and concurrent updates. See [Databases](/databases). - **Data files** (`ctx.data`) store text, JSON, and JSONL under `/data/`. See [Data files](/data-storage). - **Secrets** are named values set out-of-band and read at runtime via `ctx.secrets.get(...)`. Secret values never appear in source or logs. See [Secrets](/secrets). --- Ready to build? Start with [Getting started](/getting-started), or browse the [CLI](/cli) and [API](/api-reference) references. --- # Sites & access A **site** is a named container served at `https://.interfold.site`. It attaches to an account-owned bucket and interprets its web files, functions, cron sources, and runtime data. Buckets also work without a Site. This page covers creating sites, subdomains, and the access model that decides who can see what. ## Creating and selecting sites ```sh interfold sites create --name "My Site" --access PUBLIC interfold sites list --status ACTIVE interfold sites get ``` Site creation creates a bucket automatically. To attach existing storage: ```sh interfold buckets create --name "My files" interfold sites create --name "My Site" --bucket interfold files put ./notes.md /notes.md --bucket ``` Each bucket supports at most one Site. Directory locations are fixed: `/web`, `/api`, `/cron`, and `/data`. Other files remain private storage. Pass `--site ` as a convenience for file commands, or select storage with `--bucket `. ### Site creation limits Site creation is limited per account: - **Free:** 10 sites. - **Builder:** 10K sites. - **Platform admins:** no site cap. The site cap applies when creating a new site. Existing sites remain available when an account's subscription status changes. ### Subdomains Each site gets a subdomain, returned by `sites create` and `sites get`. Always read it from the API — never infer it from the display name. Build hosted URLs as `https://.interfold.site/`. Only files under the workspace `/web/` directory are browser-hosted. The `/web/` prefix is omitted from hosted URLs: `/web/index.html` serves at `/`, and `/web/pricing.html` serves at `/pricing.html`. Web files are served verbatim. ## The access model Buckets are account-owned storage. Reading or writing through the Files API always requires account authentication. Attaching a Site does not make the bucket, its object API, or arbitrary stored objects public. The Site's `access` setting controls only browser-hosted `/web/` files: | Site access | Anonymous `/web/` access | `/api/` runtime | | ----------- | ------------------------- | --------------------- | | `PUBLIC` | Anyone | Anyone can invoke it | | `PRIVATE` | Signed-in account members | Anyone can invoke it | ```sh interfold sites update --access PUBLIC interfold sites update --access PRIVATE ``` There are no per-file access overrides. New uploads, replacements, and renames under `/web/` follow the Site's access setting. Private Sites show a sign-in gate for web files. Functions own their authorization. A deployed `/api/` runtime is anonymous for both Site settings, so a handler that protects content must check its own cookie, token, signature, or other credential and return its own `401` or `403`. Do not use `PRIVATE` Site access as function authorization. ## What is never public These resources are always account-private, regardless of Site access: - **Function source** at `/api/*.ts` — the code is not served as a static file. Its separate runtime endpoint (`/api/`) is callable, but source remains available only through authenticated account tooling. - **Cron source** at `/cron/*.ts` — scheduled handler code has no public runtime URL. See [Cron Jobs](/cron-jobs). - **Data files** under `/data/*` — written through `ctx.data`, never served on the web. - **Database and migration assets** — database state and project migration files are never hosted as site objects. - **Other bucket objects** — use the authenticated Files or Bucket API; attaching a Site does not create a public-object feature. Inspect these with authenticated tooling: ```sh interfold files ls /data --site interfold files cat /data/state.json --site ``` ## Verifying a publish Don't trust a publish until you've checked the live URL: ```sh interfold files stat /web/index.html --site interfold sites get curl -I https://.interfold.site/index.html curl -I https://.interfold.site/ # for the homepage, check root too ``` --- Next: [Functions](/functions) · [Cron Jobs](/cron-jobs) · [Databases](/databases) · [Data files](/data-storage) · [Secrets](/secrets) --- # Functions Interfold Functions run server-side TypeScript at `/api/*` on your site. Use them for form handlers, webhooks, small APIs, and any logic that shouldn't live in the browser. No build step, no server to manage — deploy is just uploading a file. ## The contract A function is a single TypeScript file with one rule: export a named `handler` that returns a `Response`. ```ts export async function handler(req: Request, ctx: InterfoldContext) { const url = new URL(req.url) const name = url.searchParams.get('name') ?? 'world' return Response.json({ ok: true, message: `hello ${name}`, siteId: ctx.siteId, }) } ``` - **Source path:** `/api/.ts` — exactly one segment under `/api/`. - **Runtime path:** `/api/` — no `.ts` extension. - **Signature:** `handler(req: Request, ctx: InterfoldContext)`. - **Return:** a standard `Response` (use `Response.json(...)` for JSON). ## Invocation and authorization The runtime endpoint is anonymously callable for both `PUBLIC` and `PRIVATE` Sites. Site access controls only `/web/` static content; it neither exposes function source nor authorizes a function request. If a function protects content or performs a privileged action, its handler must validate its own cookie, token, signature, or other credential and return the appropriate `401` or `403`. Do not rely on a `PRIVATE` Site as an outer function gate. ### v0 limits Functions v0 runs a single self-contained file. It does **not** support: - `import` statements, npm packages, or Node built-ins - nested paths like `/api/foo/bar.ts` Keep each function to one file and the standard web `Request`/`Response` APIs. For scheduled execution, see [Cron Jobs](/cron-jobs). ## The `ctx` object Every handler receives a context object: | Property | Description | | ------------- | ---------------------------------------------------------------------- | | `ctx.siteId` | The id of the site the function belongs to. | | `ctx.data` | Text, JSON, and JSONL under `/data/`. See [Data files](/data-storage). | | `ctx.db` | SQL database queries. See [Databases](/databases). | | `ctx.secrets` | Read site secrets at runtime. See [Secrets](/secrets). | | `ctx.llm` | Call OpenAI models using the site's account usage allowance. | ## Model calls Use `ctx.llm.messages.create` from a function or cron job. No OpenAI API key, SDK, or site secret is needed. ```ts // /api/summarize.ts export async function handler(req: Request, ctx: InterfoldContext) { if (req.method !== 'POST') { return new Response('Use POST', { status: 405 }) } // Validate your application's user/session here before spending account usage. const input = await req.json().catch(() => null) if ( typeof input?.text !== 'string' || !input.text.trim() || input.text.length > 8000 ) { return Response.json( { error: 'Provide 1–8000 characters of text' }, { status: 400 } ) } const result = await ctx.llm.messages.create({ model: 'gpt-6-luna', messages: [ { role: 'system', content: 'Summarize the text in three short bullets.' }, { role: 'user', content: input.text }, ], maxOutputTokens: 4096, }) return Response.json({ summary: result.message.content }) } ``` `model` defaults to `gpt-6-luna`; `gpt-6.1-sol` is also supported. `reasoningEffort` defaults to `low` and accepts `none`, `low`, `medium`, or `high`. Only Luna supports `none`, which is useful for short classifications. `maxOutputTokens` defaults to 4,096 and accepts 16–8,192. It includes internal reasoning and formatting, not just visible text. Avoid tiny budgets with reasoning enabled, even for one-word answers. If the limit is hit, increase the budget, request a shorter answer, or lower the reasoning effort. Send 1–100 text messages using `user` and `assistant` roles, with an optional first `system` message and at least one user message. Each message is limited to 32,000 characters; combined content is limited to 64,000 UTF-8 bytes. Calls time out after 45 seconds. Streaming, images, tools, and provider-managed conversation state are not supported; send the conversation history with each call. Read the answer from `result.message.content`. The result also includes `id`, `model`, and `usage`. Calls share the site's owning account allowance with browser-agent usage. Failed calls can also consume usage. Errors include a stable `code`, an actionable `message`, and an HTTP `status` when available. Preserve the code and message in your application's error response. Uncaught model errors return their status, code, and message as JSON. Calls are not automatically retried. ## Deploying Upload the source under `/api/`: ```sh interfold files put ./hello.ts /api/hello.ts --site --content-type text/typescript ``` Then invoke the runtime path: ```sh interfold sites get curl -i "https://.interfold.site/api/hello?name=agent" ``` Functions accept any HTTP method — read `req.method` to branch: ```ts export async function handler(req: Request, ctx: InterfoldContext) { if (req.method !== 'POST') { return new Response('Method not allowed', { status: 405 }) } const body = await req.json() return Response.json({ received: body }) } ``` ## Cookies and password-protected content Same-origin cookies are available through the standard `Request` headers. A function can also return `Set-Cookie`; the browser stores it and sends it with later requests to the same site. Interfold's own reserved session cookie is not exposed to user functions and cannot be overwritten by them. Keep the protected content behind the function rather than embedding it in the public HTML. For example, configure `CONTENT_PASSWORD` and a separate random `CONTENT_SESSION_TOKEN` as [site secrets](/secrets), then deploy this as `/api/protected.ts`: ```ts function readCookie(req: Request, name: string): string { const cookieHeader = req.headers.get('cookie') ?? '' for (const cookie of cookieHeader.split(';')) { const [cookieName, ...valueParts] = cookie.trim().split('=') if (cookieName === name) { return decodeURIComponent(valueParts.join('=')) } } return '' } const privateResponseHeaders = { 'Cache-Control': 'private, no-store', } export async function handler(req: Request, ctx: InterfoldContext) { const password = await ctx.secrets.get('CONTENT_PASSWORD') const sessionToken = await ctx.secrets.get('CONTENT_SESSION_TOKEN') if (req.method === 'POST') { const body = (await req.json()) as { password?: string } if (body.password !== password) { return new Response('Unauthorized', { status: 401, headers: privateResponseHeaders, }) } return new Response(null, { status: 204, headers: { ...privateResponseHeaders, 'Set-Cookie': `protected_session=${encodeURIComponent(sessionToken)}; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=86400`, }, }) } if (readCookie(req, 'protected_session') !== sessionToken) { return new Response('Unauthorized', { status: 401, headers: privateResponseHeaders, }) } return Response.json( { content: 'The protected content goes here.' }, { headers: privateResponseHeaders } ) } ``` From the page, submit the password and then request the content. Same-origin `fetch` includes the stored cookie automatically: ```ts await fetch('/api/protected', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ password }), }) const response = await fetch('/api/protected') const { content } = await response.json() ``` ## A stateful example Combine `ctx.data` for a hit counter that survives restarts: ```ts export async function handler(req: Request, ctx: InterfoldContext) { const previous = (await ctx.data .readJson('/data/state.json') .catch(() => ({ visits: 0 }))) as { visits: number } const next = { visits: previous.visits + 1, updatedAt: new Date().toISOString(), } await ctx.data.writeJson('/data/state.json', next) return Response.json(next) } ``` ## Troubleshooting a deploy A failed deploy can leave the source saved while the function status is `failed`. Read the CLI response and check: - The path is exactly one segment under `/api/`, e.g. `/api/hello.ts`. - The file exports a named `handler`. - The handler returns a `Response`. - There are no `import`s, npm packages, or Node built-ins. Fix the source and re-upload. Then re-verify the runtime path with `curl -i`. --- Next: [Cron Jobs](/cron-jobs) for scheduled execution · [Databases](/databases) for structured data · [Data files](/data-storage) for file-shaped data · [Secrets](/secrets) for runtime config. --- # Cron Jobs Cron Jobs run a site's TypeScript on a UTC schedule. They use the same isolated runtime, site data, and site secrets as [Functions](/functions), but do not have a browser request or user session. ## The contract Create one self-contained TypeScript file under `/cron/`. Export a static five-field schedule and a named handler: ```ts export const schedule = '*/5 * * * *' export async function handler(event: CronEvent, ctx: InterfoldCronContext) { await ctx.data.writeJson('/data/cron-smoke.json', { runId: event.runId, scheduledAt: event.scheduledAt, triggeredAt: event.triggeredAt, }) } ``` - **Source path:** `/cron/.ts`, exactly one segment under `/cron/`. - **Schedule:** a string-literal, five-field cron expression. - **Time zone:** UTC. - **Minimum cadence:** five minutes. - **Signature:** `handler(event: CronEvent, ctx: InterfoldCronContext)`. - **Imports:** no imports, npm packages, or Node built-ins in v0. The schedule is extracted statically during deployment. Interfold does not execute your code to discover when it should run. ## Deploying Cron Jobs use the existing file upload command; no separate CLI command is needed: ```sh interfold files put ./smoke.ts /cron/smoke.ts \ --site \ --content-type text/typescript ``` The response includes the cron definition and deployment status. Cron source is a private workspace resource and has no public runtime URL. To verify a job that writes site data, wait for the next tick and inspect the result: ```sh interfold files cat /data/cron-smoke.json --site ``` ## Event and delivery semantics The event includes: | Property | Description | | ------------------- | ------------------------------------------------ | | `event.runId` | Stable idempotency key for this scheduled run. | | `event.scheduledAt` | Time the run was scheduled for. | | `event.triggeredAt` | Time Interfold dispatched the run. | | `event.trigger` | `SCHEDULED` in the current customer-facing flow. | Delivery is at least once. Use `runId` as an idempotency key when calling an external system. V0 does not overlap two runs of the same cron, retry failed tenant handlers automatically, or create a catch-up burst after downtime. Deleting the `/cron/*.ts` source disables future runs while preserving platform-owned run history. --- Next: [Databases](/databases) for structured data · [Data files](/data-storage) for file-shaped data · [Secrets](/secrets) for runtime configuration. --- # Databases Each Interfold site can have one SQL database. Use it for structured application data, queries, relationships, counters, and concurrent updates. Functions and Cron Jobs access it through `ctx.db`; API, CLI, MCP, and browser-agent callers can also issue a generic D1 query. If your state naturally belongs in a text, JSON, or JSONL file and writes are infrequent, use [Data files](/data-storage) instead. ## Create a database Database commands require an explicit `--site` or `--subdomain` target: ```sh interfold db create --site ``` Creation is idempotent. Running it again safely resumes provisioning or binding updates. It does not apply application migrations. ## Query a database directly Use a write-authorized API key to forward SQL and optional parameter values to the site database without deploying a Function: ```sh interfold db query --site 'SELECT id, name FROM users WHERE active = ?' --params '[true]' ``` The equivalent REST endpoint is: ```http POST /v0/sites/:siteId/databases/:databaseId/query Content-Type: application/json { "sql": "UPDATE users SET active = ? WHERE id = ?", "params": [false, 42] } ``` This is a generic D1-compatible query surface: it can read or change database data and schema, and it returns the D1-style `success`, `errors`, `messages`, and `result` envelope. It requires `WRITE` permission even for `SELECT` statements. Use placeholders for values; D1 evaluates the SQL and returns any statement-level error. Batch and raw-query variants are not part of this first surface. The browser-agent and MCP query tools use the same capability. Browser-agent queries always require user approval because they can change data. ## Cloud migration history Interfold's migration ledger lives in the site database. Agents can inspect it and apply one new migration without access to a local project or every earlier SQL file: ```http GET /v0/sites/:siteId/databases/:databaseId/migrations GET /v0/sites/:siteId/databases/:databaseId/migrations/:migrationName POST /v0/sites/:siteId/databases/:databaseId/migrations ``` The apply body contains `name`, `sql`, and `confirm: true`. One D1 transaction writes the name, SHA-256 checksum, exact SQL, and applied time together with the schema change. A successful receipt is immutable. A confirmed failure creates no migration resource, so corrected SQL may be retried under a name that has never successfully applied. `_interfold_migrations` is the authoritative successful migration resource. A receipt proves that the stored SQL committed with the receipt; it does not assert application-level correctness, represent unmanaged SQL changes, or detect arbitrary schema drift. Legacy receipts created before SQL storage was added remain visible with `sourceAvailable: false`; Interfold does not invent their source. When a request times out, Interfold leaves the short execution lease in place and checks for the receipt on retry. A missing receipt immediately after a timeout is not treated as proof of rollback. Receipt-first execution and the unique migration name prevent the same migration SQL from running twice when a later retry reaches D1. ## CLI migration files Run migration commands from the project. Interfold always uses the project-root `migrations/` directory and searches upward when a command runs in a nested folder. ```text migrations/ 0001_create_users.sql 0002_add_user_email.sql ``` ```sh interfold db migrations create create_users interfold db migrations list --site interfold db migrations apply --site --confirm ``` `list` reports successful cloud migration receipts. `apply` reads the complete ordered migration prefix from the project migration directory, validates it against provider history, and applies pending files. Applied files are immutable: if a schema must change, add a new forward migration. Interfold records names and SHA-256 checksums in `_interfold_migrations`. The Function and Cron Job runtime reserves that exact table, but the generic network query endpoint deliberately passes it through like any other D1 table. Avoid changing the ledger directly: migration validation and recovery rely on its contents. The CLI complete-prefix validation runs as part of `apply`; it is not a separate public operation or a requirement of the cloud migration resource. ## Export a database The Database page in the dashboard can create a full SQL export. Interfold keeps a history of export records so a long-running export remains visible after leaving and returning to the page. Only one export can be in progress for a database. API-key clients can use the equivalent resource endpoints: ```http POST /v0/sites/:siteId/databases/:databaseId/exports GET /v0/sites/:siteId/databases/:databaseId/exports POST /v0/sites/:siteId/databases/:databaseId/exports/:exportId/reconcile ``` When a create or reconcile response is `PROCESSING`, keep calling reconcile with the export ID until the status is `COMPLETE` or `ERROR`. The dashboard does this automatically for processing records; the CLI does not run a poller yet. Completed records remain in history after their temporary download URL expires. ## Runtime interface ```ts const rows = await ctx.db.query('SELECT id, name FROM users WHERE active = ?', [ true, ]) const user = await ctx.db.first('SELECT * FROM users WHERE id = ?', [1]) const result = await ctx.db.execute('INSERT INTO users (name) VALUES (?)', [ 'Ada', ]) ``` `execute()` returns an Interfold-owned result: ```ts { changes: number lastInsertRowId: number | null } ``` `batch()` returns one result per statement with `rows`, `changes`, and `lastInsertRowId`. Provider metadata is never part of the `ctx.db` runtime contract; the direct Query API intentionally preserves the D1 response envelope and metadata. Use SQL placeholders for values. A batch is atomic; separate `ctx.db` calls are not one transaction. Runtime failures expose a stable `DATABASE_*` code without provider diagnostics. ## Permanently delete a database Deletion deliberately takes two commands. The first returns a short-lived code and a warning; the second supplies that code: ```sh interfold db delete --site interfold db delete --site --confirm DELETE-XXXXXXXX ``` The code is bound to that site database and expires after ten minutes. Deletion removes the database binding before deleting the provider resource. Local migration files remain. Export the database first if you need a copy; deletion cannot be undone. --- # Data files `ctx.data` gives [functions](/functions) and [cron jobs](/cron-jobs) a simple, file-native persistence layer under `/data/`. It's the fastest way to store settings, drafts, text, and simple event logs without provisioning a database. Use Data files when your application state naturally belongs in a text, JSON, or JSONL file and writes are infrequent. For structured application data, queries, relationships, counters, or concurrent updates, use a [Database](/databases). Data files are ordinary site files: visible to authenticated tooling, but never served on public hosted URLs. ## Storage usage and billing File storage is measured across your account by file size and time retained. Static files, `/data` files, function source, and cron source count, including files on archived sites. Deleting a file stops its contribution. Historical revisions are currently excluded from customer storage usage. The retention and pricing policy for retained history is under review. Free includes 1 GB; monthly Builder includes 25 GB. New Builder subscriptions include storage overage billing. For activated subscriptions, overage costs **$0.030666… per GB-month** after the included allowance, billed with your subscription. One GB is 1,073,741,824 bytes; a month is your actual subscription billing period. Request costs are included in this storage rate. The allowance is applied once to the period's size × time usage. For example, 100 GB retained for an entire Builder billing period produces 75 GB-month of overage, or **$2.30** before taxes and discounts. Activation starts measurement from that point forward; earlier usage is not backfilled. See **Usage → File storage** in the [dashboard](https://app.interfold.dev/usage) for stored bytes, included storage, estimated overage, and whether billing is active. Existing subscriptions without storage billing attached remain inactive. ## Helpers Inside a function or cron handler, reach for `ctx.data`: ```ts // Text await ctx.data.read('/data/notes.txt') await ctx.data.write('/data/notes.txt', 'hello') await ctx.data.delete('/data/notes.txt') await ctx.data.info('/data/notes.txt') // JSON await ctx.data.readJson('/data/settings.json') await ctx.data.writeJson('/data/settings.json', { theme: 'dark' }) // JSONL (append-only logs) await ctx.data.appendJsonl('/data/events.jsonl', { type: 'created' }) await ctx.data.tailJsonl('/data/events.jsonl', 100) ``` ## Extension rules The structured helpers require matching file extensions: | Helper | Required extension | | -------------------------- | ------------------ | | `readJson`, `writeJson` | `.json` | | `appendJsonl`, `tailJsonl` | `.jsonl` | | `read`, `write` | any | ## Patterns ### JSON document A single evolving document — settings, a small record, aggregate state: ```ts export async function handler(req: Request, ctx: InterfoldContext) { const settings = await ctx.data .readJson('/data/settings.json') .catch(() => ({ theme: 'light' })) return Response.json(settings) } ``` ### JSONL event log Append-only records — form submissions, analytics, audit trails: ```ts export async function handler(req: Request, ctx: InterfoldContext) { await ctx.data.appendJsonl('/data/signups.jsonl', { email: (await req.json()).email, at: new Date().toISOString(), }) const recent = await ctx.data.tailJsonl('/data/signups.jsonl', 20) return Response.json({ recent }) } ``` ## Concurrency Data file writes create file revisions. The Files API and MCP can reject a stale replacement when given the current version ID. `ctx.data` uses version checks for its read-modify-write operations. For shared state needing transactions across records, use a [Database](/databases). For logs, drafts, settings, and other low-contention state, `ctx.data` is ideal. ## Inspecting data Data lives at `/data/*` and is not a public URL. Read it with authenticated tooling: ```sh interfold files ls /data --site interfold files cat /data/settings.json --site ``` --- Next: [Databases](/databases) for structured application data · [Secrets](/secrets) for runtime configuration. --- # Secrets Site secrets hold values your [functions](/functions) and [cron jobs](/cron-jobs) need at runtime — API keys, tokens, webhook signing keys — without ever writing them into source, config, or logs. ## Setting a secret Set secrets through the CLI, and always pass the value via **stdin** so it never lands in your shell history or process list: ```sh printf '%s' "$OPENAI_API_KEY" | interfold secrets set OPENAI_API_KEY --site ``` List the secrets on a site (names and metadata only — never values): ```sh interfold secrets list --site ``` Remove one: ```sh interfold secrets rm OPENAI_API_KEY --site ``` Secret names may contain letters, numbers, and underscores. Empty values are valid. ## Reading a secret in a handler Functions and cron jobs access secrets at runtime through `ctx.secrets`: ```ts export async function handler(req: Request, ctx: InterfoldContext) { const apiKey = await ctx.secrets.get('OPENAI_API_KEY') if (!apiKey) { return new Response('Not configured', { status: 503 }) } // Use apiKey to call an upstream service… return Response.json({ configured: true }) } ``` Never return a secret value in a response or log it. Treat `ctx.secrets.get(...)` output as sensitive. ## Verifying without revealing Prefer `secrets list` to confirm a secret exists. Only use `secrets get` when you explicitly need to reveal the value: ```sh interfold secrets list --site # check existence interfold secrets get OPENAI_API_KEY --site --raw # reveal (rare) ``` ## Good practice - Store third-party credentials as secrets, not in function source. - Rotate by re-running `secrets set` with the new value — it replaces in place. - Keep secret names descriptive and stable; functions reference them by name. --- Next: revisit [Functions](/functions) for a live endpoint · [Cron Jobs](/cron-jobs) for scheduled work. --- # REST API The Interfold REST API is the canonical contract beneath the CLI and MCP server. Use it to integrate Interfold with another system or from any language that can send HTTPS requests. - **Base URL:** `https://api.interfold.dev/v0` - **Format:** JSON request and response bodies unless an operation says otherwise. - **Convention:** `POST` creates and updates resources, `PUT` writes raw objects, `DELETE` deletes, and `GET` reads. ## Start here - [Quickstart](/api-reference/quickstart) — make an authenticated request. - [Authentication & permissions](/api-reference/authentication) — create and protect API keys. - [Errors](/api-reference/errors) — parse failures consistently. - [Pagination](/api-reference/pagination) — walk list results. - [Rate limits](/api-reference/rate-limits) — respect account request budgets. ## Choose an interface The REST API, CLI, and MCP server expose related capabilities but have different operating models. | Interface | Use it for | | --------------- | ----------------------------------------------------------------------------- | | **REST API** | Integrations, services, and direct resource control. | | [**CLI**](/cli) | Local development, shell automation, credential storage, and project context. | | [**MCP**](/mcp) | Agent clients that support remote MCP tools and approval flows. | REST is the canonical resource contract. CLI and MCP pages link back to the same concepts without duplicating the HTTP reference. ## Resources - [Accounts](/api-reference/accounts) - [Sites](/api-reference/sites) - [Buckets](/api-reference/buckets) - [Files](/api-reference/files) - [Functions](/api-reference/functions) - [Databases](/api-reference/databases) - [Secrets](/api-reference/secrets) ## Versioning The version in the path is the compatibility boundary. The current public API is `/v0`. Breaking changes require a new API version. Removing or renaming a field, changing a field type, changing authentication requirements, or changing the meaning of an existing parameter is breaking. Adding endpoints, optional request fields, response fields, or new enum values is non-breaking when clients already tolerate unknown values. New integrations should use the latest documented version. ## Machine-readable documentation Every reference page has a **View as Markdown** link. The complete documentation is also available through [llms.txt](/llms.txt) and [llms-full.txt](/llms-full.txt). --- # API quickstart Make one authenticated request to list the sites in your account. ## 1. Create an API key Open **API Keys** in the Interfold dashboard and create a **Read-only** key. Choose **Read/write** only when the integration needs to change resources. Store the key in a server-side environment variable. Never put it in browser code, commit it to a repository, or paste it into chat. ```sh export INTERFOLD_API_KEY='' export INTERFOLD_ACCOUNT_ID='' ``` ## 2. List sites ```sh curl "https://api.interfold.dev/v0/sites?accountId=$INTERFOLD_ACCOUNT_ID" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ``` The response contains a page of sites: ```json { "sites": [], "pagination": { "hasMore": false, "nextOffset": null } } ``` ## 3. Create a site Use a Read/write key for mutations: ```sh curl -X POST "https://api.interfold.dev/v0/sites" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "accountId": "", "name": "My Site", "access": "PRIVATE" }' ``` The response includes the Site ID, generated subdomain, attached bucket, and access state. Use [Get a site](/api-reference/sites#get-a-site) before deriving a hosted URL; do not guess the subdomain from the name. ## Next steps - [Authentication & permissions](/api-reference/authentication) - [Sites](/api-reference/sites) - [Files](/api-reference/files) - [Errors](/api-reference/errors) --- # Authentication & permissions Authenticate every REST request with an Interfold API key. ## Headers Bearer authentication is recommended: ```http Authorization: Bearer ``` The equivalent API-key header is also accepted: ```http X-API-Key: ``` A missing or invalid key returns `401 Unauthorized` with the REST error envelope: `{"error":{"code":"unauthorized","message":"..."}}`. ## Keep keys private API keys are server-side credentials. Do not ship them in browser code, commit them to project files, paste them into chat, or include them in public logs. Create and revoke keys from the dashboard. ## Permissions Manual keys have one fixed permission: | Permission | Allows | | ---------- | ----------------------------------------------------------------------------------------------------------------- | | `READ` | Reads, including file contents, secret values, migration receipts, and MCP read tools. | | `WRITE` | Every read plus creation, updates, uploads, deployments, generic database queries, migration apply, and deletion. | Read-only keys allow `GET`, `HEAD`, and `OPTIONS`. They also allow MCP transport requests whose selected tool is read-only. `POST /v0/sites/:siteId/databases/:databaseId/query` requires `WRITE`, even when its SQL only reads data, because the generic query surface can also change data and schema. Other writes return `403 Forbidden` before the operation runs. Permissions cannot be changed after creation; revoke the key and create a replacement. ## Account scope Each API key belongs to exactly one account. Use [Get current account](/api-reference/accounts#get-current-account) to resolve that account without storing a second account identifier. Resource authorization still applies. A valid key cannot operate on resources owned by another account. ## Browser-only operations Some dashboard operations require an interactive user identity and are not part of the API-key contract. These include managing API keys, account membership, billing, and user-owned agent approvals. The operation sections in this reference describe the supported API-key surface. --- # Errors Interfold uses HTTP status codes and a consistent JSON error envelope. ## Error envelope ```json { "error": { "code": "not_found", "message": "Site not found" } } ``` Every REST API error body is rooted at `error`. Use the stable, generic snake-case `error.code` for branching and `error.message` for people or logs. Do not expect an HTTP status field, a top-level `message`, or top-level recovery fields. Some operations include useful validation or recovery metadata in `error.details`. It is omitted when there is no meaningful structured metadata. For example, a migration conflict can include its operation-specific code and a safe retry instruction without changing the generic `conflict` code: ```json { "error": { "code": "conflict", "message": "Another migration apply is active", "details": { "code": "MIGRATION_LOCKED", "retryable": true, "nextAction": "RETRY_MIGRATIONS_APPLY", "nextCommand": "interfold db migrations apply --site site_123 --confirm" } } } ``` Treat `details` as operation-specific metadata. Preserve it when relaying a failure, but branch on it only where the operation documents that behavior. ## Status codes | Status | `error.code` | Meaning | | ------ | ------------------------- | ---------------------------------------------------------- | | `400` | `bad_request` | Validation failed or the request is malformed. | | `401` | `unauthorized` | Authentication is missing or invalid. | | `403` | `forbidden` | The caller or key permission cannot perform the operation. | | `404` | `not_found` | The resource does not exist or is not visible to the caller. | | `405` | `method_not_allowed` | The HTTP method is not supported. | | `409` | `conflict` | The requested change conflicts with current state. | | `413` | `payload_too_large` | The request body is too large. | | `422` | `unprocessable_entity` | The request is valid but cannot be completed. | | `429` | `too_many_requests` | The account exceeded its request budget. | | `500` | `internal_server_error` | An unexpected Interfold failure occurred. | | `502` | `bad_gateway` | An upstream provider failed. | | `503` | `service_unavailable` | A required service is unavailable. | | `504` | `gateway_timeout` | An upstream request timed out. | ## Retry safely Do not retry every failure automatically. - Fix `400`, `401`, `403`, and `422` responses before retrying. - Re-read the resource after ambiguous write failures. - Respect `Retry-After` on `429` responses. - Use structured migration `error.details.nextAction` and `error.details.nextCommand` when present. - Do not retry an external side effect when the first result is unknown unless the operation documents idempotency. ## Request IDs When a response includes a request or operation identifier, record it with the status, error code, and timestamp. Include those details when reporting a problem. ## Transport exceptions The raw object `GET` and `HEAD` endpoints can stream file content. Failures detected before streaming begins use this JSON envelope. If streaming has already started, HTTP cannot replace the body with JSON; Interfold safely ends that stream instead. Hosted function and cron responses are application responses supplied by the Site, rather than REST API error bodies. MCP also has its own protocol-level tool-error result; its client preserves the REST `code`, `message`, and `details` when an underlying REST call fails. --- # Pagination Every collection endpoint uses bounded `limit` and `offset` query fields and returns a resource-specific array plus the same pagination metadata. ## Query fields | Field | Default | Limits | | -------- | ------- | ------------------------------------- | | `limit` | `50` | Integer from `1` through `100`. | | `offset` | `0` | Integer greater than or equal to `0`. | ## Response Responses retain the resource name (`sites`, `buckets`, `files`, and so on) and include pagination metadata. `nextOffset` is a usable value only while `hasMore` is true; it is otherwise `null`. ```json { "sites": [], "pagination": { "hasMore": false, "nextOffset": null } } ``` An empty result is `200 OK` with an empty array, not `null` or `404`. ## Walk every page Use `pagination.nextOffset` until `pagination.hasMore` is `false`. ```sh offset=0 limit=50 while :; do response="$(curl -sS \ "https://api.interfold.dev/v0/sites?accountId=$INTERFOLD_ACCOUNT_ID&limit=$limit&offset=$offset" \ -H "Authorization: Bearer $INTERFOLD_API_KEY")" # Process response.sites here. if [ "$(printf '%s' "$response" | jq -r '.pagination.hasMore')" != "true" ]; then break fi offset="$(printf '%s' "$response" | jq -r '.pagination.nextOffset')" done ``` Do not infer another page from `sites.length === limit`; that fails when the total happens to be an exact multiple of the page size. --- # Rate limits Interfold applies an account-wide request budget to authenticated API traffic. ## Current limit API-key traffic is limited to **600 requests per account per 60-second fixed window**. Every API key for an account shares that one budget: there are no separate limits for reads, writes, resources, or plans. API-key requests to the `/v0` REST API and `/mcp` consume the same budget. Browser-authenticated dashboard sessions and unauthenticated routes are not subject to this API-key limit. ## Headers Responses can include: | Header | Meaning | | ----------------------- | ---------------------------------------------- | | `X-RateLimit-Limit` | Requests allowed in the current window. | | `X-RateLimit-Remaining` | Requests remaining in the current window. | | `X-RateLimit-Reset` | Unix timestamp when the current window resets. | | `Retry-After` | Seconds to wait after a `429` response. | ## Exceeded limits A request over the limit returns `429 Too Many Requests` with the standard error envelope. ```json { "error": { "code": "too_many_requests", "message": "Too many requests" } } ``` Wait for `Retry-After`, add jitter, and retry only operations that are safe to repeat. Avoid tight polling loops; prefer durable status fields and bounded reconciliation calls. ## Scope The budget follows the account rather than an individual API key. Rotating keys does not create a second request budget. --- # Accounts Resolve the API key account and read or update account metadata. | Method | Operation | Path | | --- | --- | --- | | **`GET`** | [Get current account](#get-current-account) | `/v0/accounts/current` | | **`GET`** | [Get an account](#get-an-account) | `/v0/accounts/:accountId` | | **`POST`** | [Update an account](#update-an-account) | `/v0/accounts/:accountId` | ## Get current account Resolve the account that owns the current API key. **`GET`** `/v0/accounts/current` - **API key permission:** Read-only or Read/write ### Request ~~~sh curl \ "https://api.interfold.dev/v0/accounts/current" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "id": "", "name": "Acme" } ~~~ ### Behavior and errors - This operation requires API key authentication. ### Related interfaces - **CLI:** `interfold accounts current` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Get an account Read an account that the authenticated caller can access. **`GET`** `/v0/accounts/:accountId` - **API key permission:** Read-only or Read/write ### Parameters - `accountId` — account UUID. ### Request ~~~sh curl \ "https://api.interfold.dev/v0/accounts/" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "id": "", "name": "Acme" } ~~~ See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Update an account Change the account name. **`POST`** `/v0/accounts/:accountId` - **API key permission:** Read/write ### Parameters - `accountId` — account UUID. - `name` — required string, 1–100 characters after trimming. ### Request ~~~sh curl -X POST \ "https://api.interfold.dev/v0/accounts/" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "name": "Acme Studio"}' ~~~ ### Response ~~~json { "id": "", "name": "Acme Studio" } ~~~ ### Behavior and errors - Only account administrators can update an account. See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. ## Shared behavior All operations use the [API authentication](/api-reference/authentication), [error](/api-reference/errors), and [rate-limit](/api-reference/rate-limits) contracts. List operations use [standard pagination](/api-reference/pagination) unless the operation says otherwise. --- # Sites Create hosted identities, attach buckets, and control public or private access. | Method | Operation | Path | | --- | --- | --- | | **`GET`** | [List sites](#list-sites) | `/v0/sites` | | **`POST`** | [Create a site](#create-a-site) | `/v0/sites` | | **`GET`** | [Get a site](#get-a-site) | `/v0/sites/:siteId` | | **`POST`** | [Update a site](#update-a-site) | `/v0/sites/:siteId` | ## List sites List sites in an account, newest updates first. **`GET`** `/v0/sites` - **API key permission:** Read-only or Read/write ### Parameters - `accountId` — required account UUID. - `bucketId` — optional exact bucket UUID. - `subdomain` — optional exact subdomain. - `status` — optional `ACTIVE` or `ARCHIVED`. - `limit` and `offset` — standard pagination fields. ### Request ~~~sh curl \ "https://api.interfold.dev/v0/sites" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "sites": [{ "id": "", "name": "Docs", "subdomain": "docs-example", "access": "PUBLIC", "status": "ACTIVE", "bucketId": "" }], "pagination": { "hasMore": false, "nextOffset": null } } ~~~ ### Related interfaces - **CLI:** `interfold sites list` - **MCP:** `list_sites` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Create a site Create a site and attach new or existing storage. **`POST`** `/v0/sites` - **API key permission:** Read/write ### Parameters - `accountId` — required account UUID. - `name` — required string, 1–100 characters after trimming. - `subdomain` — optional lowercase subdomain, 3–63 characters. - `access` — optional `PUBLIC` or `PRIVATE`. - `bucketId` — optional existing bucket UUID. Omit it to create storage automatically. ### Request ~~~sh curl -X POST \ "https://api.interfold.dev/v0/sites" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "accountId": "", "name": "Docs", "subdomain": "docs-example", "access": "PUBLIC"}' ~~~ ### Response ~~~json { "id": "", "name": "Docs", "subdomain": "docs-example", "access": "PUBLIC", "status": "ACTIVE", "bucketId": "" } ~~~ ### Behavior and errors - A requested subdomain can return `409 Conflict` when it is reserved or already taken. - Site limits return `422 Unprocessable Entity`. ### Related interfaces - **CLI:** `interfold sites create --name "Docs" --access PUBLIC` - **MCP:** `create_site` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Get a site Read site metadata, its attached bucket, and runtime reconciliation status. **`GET`** `/v0/sites/:siteId` - **API key permission:** Read-only or Read/write ### Parameters - `siteId` — site UUID. ### Request ~~~sh curl \ "https://api.interfold.dev/v0/sites/" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "id": "", "name": "Docs", "subdomain": "docs-example", "access": "PUBLIC", "status": "ACTIVE", "bucketId": "" } ~~~ ### Related interfaces - **CLI:** `interfold sites get ` - **MCP:** `get_site` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Update a site Change site metadata or retry runtime reconciliation. **`POST`** `/v0/sites/:siteId` - **API key permission:** Read/write ### Parameters - `siteId` — site UUID. - `name` — optional string, 1–100 characters. - `access` — optional `PUBLIC` or `PRIVATE`. - `status` — optional `ACTIVE` or `ARCHIVED`. - `reconcile` — optional literal `true` to retry runtime reconciliation. ### Request ~~~sh curl -X POST \ "https://api.interfold.dev/v0/sites/" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "access": "PRIVATE"}' ~~~ ### Response ~~~json { "id": "", "name": "Docs", "subdomain": "docs-example", "access": "PUBLIC", "status": "ACTIVE", "bucketId": "" } ~~~ ### Behavior and errors - At least one update field is required. - An archived site must be activated before its runtime sources can be reconciled. ### Related interfaces - **CLI:** `interfold sites update --access PRIVATE` - **MCP:** `update_site` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. ## Shared behavior All operations use the [API authentication](/api-reference/authentication), [error](/api-reference/errors), and [rate-limit](/api-reference/rate-limits) contracts. List operations use [standard pagination](/api-reference/pagination) unless the operation says otherwise. --- # Buckets Manage account-owned storage independently from the sites that serve it. | Method | Operation | Path | | --- | --- | --- | | **`GET`** | [List buckets](#list-buckets) | `/v0/buckets` | | **`POST`** | [Create a bucket](#create-a-bucket) | `/v0/buckets` | | **`GET`** | [Get a bucket](#get-a-bucket) | `/v0/buckets/:bucketId` | | **`POST`** | [Update a bucket](#update-a-bucket) | `/v0/buckets/:bucketId` | ## List buckets List buckets in an account. **`GET`** `/v0/buckets` - **API key permission:** Read-only or Read/write ### Parameters - `accountId` — required account UUID. - `limit` and `offset` — standard pagination fields. ### Request ~~~sh curl \ "https://api.interfold.dev/v0/buckets" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "buckets": [{ "id": "", "appAccountId": "", "name": "Website files", "createdAt": "2026-09-20T12:00:00.000Z", "updatedAt": "2026-09-20T12:00:00.000Z" }], "pagination": { "hasMore": false, "nextOffset": null } } ~~~ ### Related interfaces - **CLI:** `interfold buckets list` - **MCP:** `list_buckets` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Create a bucket Create account-owned file storage. **`POST`** `/v0/buckets` - **API key permission:** Read/write ### Parameters - `accountId` — required account UUID. - `name` — required string, 1–100 characters. ### Request ~~~sh curl -X POST \ "https://api.interfold.dev/v0/buckets" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "accountId": "", "name": "Website files"}' ~~~ ### Response ~~~json { "id": "", "appAccountId": "", "name": "Website files", "createdAt": "2026-09-20T12:00:00.000Z", "updatedAt": "2026-09-20T12:00:00.000Z" } ~~~ ### Related interfaces - **CLI:** `interfold buckets create --name "Website files"` - **MCP:** `create_bucket` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Get a bucket Read bucket metadata. **`GET`** `/v0/buckets/:bucketId` - **API key permission:** Read-only or Read/write ### Parameters - `bucketId` — bucket UUID. ### Request ~~~sh curl \ "https://api.interfold.dev/v0/buckets/" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "id": "", "appAccountId": "", "name": "Website files", "createdAt": "2026-09-20T12:00:00.000Z", "updatedAt": "2026-09-20T12:00:00.000Z" } ~~~ ### Related interfaces - **CLI:** `interfold buckets get ` - **MCP:** `get_bucket` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Update a bucket Rename a bucket. **`POST`** `/v0/buckets/:bucketId` - **API key permission:** Read/write ### Parameters - `bucketId` — bucket UUID. - `name` — required string, 1–100 characters. ### Request ~~~sh curl -X POST \ "https://api.interfold.dev/v0/buckets/" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "name": "Production files"}' ~~~ ### Response ~~~json { "id": "", "appAccountId": "", "name": "Website files", "createdAt": "2026-09-20T12:00:00.000Z", "updatedAt": "2026-09-20T12:00:00.000Z" } ~~~ ### Related interfaces - **CLI:** `interfold buckets update --name "Production files"` - **MCP:** `update_bucket` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. ## Shared behavior All operations use the [API authentication](/api-reference/authentication), [error](/api-reference/errors), and [rate-limit](/api-reference/rate-limits) contracts. List operations use [standard pagination](/api-reference/pagination) unless the operation says otherwise. --- # Files List, read, write, and delete files by path; inspect and restore revisions by stable file ID. | Method | Operation | Path | | --- | --- | --- | | **`GET`** | [List files](#list-files) | `/v0/buckets/:bucketId/objects` | | **`GET`** | [Read a file](#read-a-file) | `/v0/buckets/:bucketId/objects/*` | | **`HEAD`** | [Inspect a file](#inspect-a-file) | `/v0/buckets/:bucketId/objects/*` | | **`PUT`** | [Write a file](#write-a-file) | `/v0/buckets/:bucketId/objects/*` | | **`DELETE`** | [Delete a file](#delete-a-file) | `/v0/buckets/:bucketId/objects/*` | | **`GET`** | [List file versions](#list-file-versions) | `/v0/files/:fileId/versions` | | **`GET`** | [Read a file version](#read-a-file-version) | `/v0/files/:fileId/versions/:versionId/content` | | **`POST`** | [Restore a file version](#restore-a-file-version) | `/v0/files/:fileId/restore` | ## List files List file metadata in a bucket. **`GET`** `/v0/buckets/:bucketId/objects` - **API key permission:** Read-only or Read/write ### Parameters - `bucketId` — bucket UUID. - `path` — optional exact normalized path. - `prefix` — optional normalized path prefix. - `limit` and `offset` — standard pagination fields. ### Request ~~~sh curl \ "https://api.interfold.dev/v0/buckets//objects" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "files": [{ "id": "", "bucketId": "", "path": "web/index.html", "contentType": "text/html; charset=utf-8", "bytes": 1480, "currentVersionId": "" }], "pagination": { "hasMore": false, "nextOffset": null } } ~~~ ### Related interfaces - **CLI:** `interfold files ls --bucket ` - **MCP:** `list_files` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Read a file Stream raw file content by normalized path. **`GET`** `/v0/buckets/:bucketId/objects/*` - **API key permission:** Read-only or Read/write ### Parameters - `bucketId` — bucket UUID. - `*` — file path, such as `web/index.html`. ### Request ~~~sh curl \ "https://api.interfold.dev/v0/buckets//objects/" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~text ~~~ ### Behavior and errors - The response uses the stored `Content-Type` and `Content-Length`. - Authenticated object reads use `Cache-Control: private, no-store`. ### Related interfaces - **CLI:** `interfold files cat /web/index.html --bucket ` - **MCP:** `read_file (text files up to 256 KiB)` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Inspect a file Read object headers without downloading its body. **`HEAD`** `/v0/buckets/:bucketId/objects/*` - **API key permission:** Read-only or Read/write ### Parameters - `bucketId` — bucket UUID. - `*` — file path. ### Request ~~~sh curl -X HEAD \ "https://api.interfold.dev/v0/buckets//objects/" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~http Content-Type: text/html; charset=utf-8 Content-Length: 1480 Interfold-File-Id: ~~~ ### Behavior and errors - The response also includes `Interfold-Version-Id` when a current revision exists. ### Related interfaces - **CLI:** `interfold files stat /web/index.html --bucket ` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Write a file Create or replace a file using the request body as raw bytes. **`PUT`** `/v0/buckets/:bucketId/objects/*` - **API key permission:** Read/write ### Parameters - `bucketId` — bucket UUID. - `*` — destination file path. - `Content-Type` — stored with the file; defaults to `application/octet-stream`. - `If-Match` — optional current version UUID; stale writes return 409. ### Request ~~~sh curl -X PUT \ "https://api.interfold.dev/v0/buckets//objects/" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" \ -H "Content-Type: text/html; charset=utf-8" \ --data-binary @ ~~~ ### Response ~~~json { "id": "", "bucketId": "", "path": "web/index.html", "contentType": "text/html; charset=utf-8", "bytes": 1480, "fileId": "", "versionId": "", "deployment": { "siteId": "", "sourcePath": "web/index.html", "status": "READY" } } ~~~ ### Behavior and errors - Writes accept no query parameters. - Every write creates a new immutable revision. The file ID stays stable across overwrites and renames. - An attached site serves static file changes immediately. - Writing `/api/*.ts` or `/cron/*.ts` also deploys the runtime source. Inspect the optional `deployment.status`; saving the file does not prove the runtime is ready. ### Related interfaces - **CLI:** `interfold files put ./index.html /web/index.html --bucket ` - **MCP:** `write_file (text files)` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Delete a file Delete a file and reconcile any attached runtime source. **`DELETE`** `/v0/buckets/:bucketId/objects/*` - **API key permission:** Read/write ### Parameters - `bucketId` — bucket UUID. - `*` — file path. ### Request ~~~sh curl -X DELETE \ "https://api.interfold.dev/v0/buckets//objects/" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "id": "", "bucketId": "", "path": "web/old.html" } ~~~ ### Behavior and errors - Deleting function or cron source also removes or pauses its deployed runtime. ### Related interfaces - **CLI:** `interfold files rm /web/old.html --bucket ` - **MCP:** `delete_file` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## List file versions List retained revisions newest first. **`GET`** `/v0/files/:fileId/versions` - **API key permission:** Read-only or Read/write ### Parameters - `fileId` — stable file UUID. - `limit` and `offset` — standard pagination fields. ### Request ~~~sh curl \ "https://api.interfold.dev/v0/files/:fileId/versions" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "fileId": "", "currentVersionId": "", "versions": [{ "id": "", "bytes": 1480, "contentType": "text/html", "createdAt": "", "restoredFromVersionId": null }], "pagination": { "hasMore": false, "nextOffset": null } } ~~~ ### Related interfaces - **CLI:** `interfold files history ls ` - **MCP:** `list_file_versions` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Read a file version Stream exact historical bytes for a retained revision. **`GET`** `/v0/files/:fileId/versions/:versionId/content` - **API key permission:** Read-only or Read/write ### Parameters - `fileId` — stable file UUID. - `versionId` — revision UUID. ### Request ~~~sh curl \ "https://api.interfold.dev/v0/files/:fileId/versions/:versionId/content" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~text ~~~ ### Behavior and errors - For binary or large revisions, use `interfold files history get `. ### Related interfaces - **CLI:** `interfold files history cat ` - **MCP:** `read_file_version (text files up to 256 KiB)` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Restore a file version Copy historical content into a new current revision. **`POST`** `/v0/files/:fileId/restore` - **API key permission:** Read/write ### Parameters - `fileId` — stable file UUID. ### Request ~~~sh curl -X POST \ "https://api.interfold.dev/v0/files/:fileId/restore" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" \ -H "Content-Type: application/json" \ --data-binary @ ~~~ ### Response ~~~json { "fileId": "", "versionId": "", "restoredFromVersionId": "", "path": "web/index.html" } ~~~ ### Behavior and errors - A stale current version returns 409. Restore preserves the current path and access rules and reconciles function or cron source. ### Related interfaces - **CLI:** `interfold files history restore ` - **MCP:** `restore_file_version` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. ## Shared behavior All operations use the [API authentication](/api-reference/authentication), [error](/api-reference/errors), and [rate-limit](/api-reference/rate-limits) contracts. List operations use [standard pagination](/api-reference/pagination) unless the operation says otherwise. --- # Functions Inspect deployed functions or explicitly deploy uploaded function source. | Method | Operation | Path | | --- | --- | --- | | **`GET`** | [List functions](#list-functions) | `/v0/sites/:siteId/functions` | | **`POST`** | [Deploy a function](#deploy-a-function) | `/v0/sites/:siteId/functions/deploy` | ## List functions List deployed function records for a site. **`GET`** `/v0/sites/:siteId/functions` - **API key permission:** Read-only or Read/write ### Parameters - `siteId` — site UUID. - `limit` and `offset` — standard pagination fields. ### Request ~~~sh curl \ "https://api.interfold.dev/v0/sites//functions" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "functions": [{ "id": "", "path": "api/hello.ts", "status": "ACTIVE" }], "pagination": { "hasMore": false, "nextOffset": null } } ~~~ ### Related interfaces - **MCP:** `list_functions` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Deploy a function Deploy function source already stored in the site bucket. **`POST`** `/v0/sites/:siteId/functions/deploy` - **API key permission:** Read/write ### Parameters - `siteId` — active site UUID. - `path` — required function source path. ### Request ~~~sh curl -X POST \ "https://api.interfold.dev/v0/sites//functions/deploy" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "path": "api/hello.ts"}' ~~~ ### Response ~~~json { "function": { "id": "", "path": "api/hello.ts", "status": "ACTIVE" } } ~~~ ### Behavior and errors - The everyday deployment path is to write `/api/.ts` through the object API or CLI. - Compilation failures return a structured function record with `422` or `500`. See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. ## Shared behavior All operations use the [API authentication](/api-reference/authentication), [error](/api-reference/errors), and [rate-limit](/api-reference/rate-limits) contracts. List operations use [standard pagination](/api-reference/pagination) unless the operation says otherwise. --- # Databases Provision a site database, run generic D1 queries, manage ordered migrations, export data, and delete safely. | Method | Operation | Path | | --- | --- | --- | | **`GET`** | [List databases](#list-databases) | `/v0/sites/:siteId/databases` | | **`POST`** | [Create a database](#create-a-database) | `/v0/sites/:siteId/databases` | | **`POST`** | [Query a database](#query-a-database) | `/v0/sites/:siteId/databases/:databaseId/query` | | **`GET`** | [List migration history](#list-migration-history) | `/v0/sites/:siteId/databases/:databaseId/migrations` | | **`GET`** | [Get a migration](#get-a-migration) | `/v0/sites/:siteId/databases/:databaseId/migrations/:migrationName` | | **`POST`** | [Apply one migration](#apply-one-migration) | `/v0/sites/:siteId/databases/:databaseId/migrations` | | **`POST`** | [Apply migrations](#apply-migrations) | `/v0/sites/:siteId/databases/:databaseId/migrations/apply` | | **`POST`** | [Create a deletion challenge](#create-a-deletion-challenge) | `/v0/sites/:siteId/databases/:databaseId/deletion-challenges` | | **`DELETE`** | [Delete a database](#delete-a-database) | `/v0/sites/:siteId/databases/:databaseId` | | **`GET`** | [List database exports](#list-database-exports) | `/v0/sites/:siteId/databases/:databaseId/exports` | | **`POST`** | [Create a database export](#create-a-database-export) | `/v0/sites/:siteId/databases/:databaseId/exports` | | **`POST`** | [Reconcile a database export](#reconcile-a-database-export) | `/v0/sites/:siteId/databases/:databaseId/exports/:exportId/reconcile` | ## List databases List the site-scoped database when one exists. **`GET`** `/v0/sites/:siteId/databases` - **API key permission:** Read-only or Read/write ### Parameters - `siteId` — site UUID. - `limit` and `offset` — standard pagination fields. ### Request ~~~sh curl \ "https://api.interfold.dev/v0/sites//databases" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "databases": [], "pagination": { "hasMore": false, "nextOffset": null } } ~~~ ### Related interfaces - **MCP:** `list_databases` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Create a database Create or resume provisioning the site database. **`POST`** `/v0/sites/:siteId/databases` - **API key permission:** Read/write ### Parameters - `siteId` — active site UUID. ### Request ~~~sh curl -X POST \ "https://api.interfold.dev/v0/sites//databases" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "database": { "id": "", "status": "READY" } } ~~~ ### Related interfaces - **CLI:** `interfold db create --site ` - **MCP:** `create_database` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Query a database Forward generic SQL to the site database without deploying a Function. **`POST`** `/v0/sites/:siteId/databases/:databaseId/query` - **API key permission:** Read/write ### Parameters - `siteId` — active site UUID. - `databaseId` — database UUID. - `sql` — required SQL forwarded to D1. - `params` — optional array of string, number, boolean, or null placeholder values. ### Request ~~~sh curl -X POST \ "https://api.interfold.dev/v0/sites//databases//query" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "sql": "SELECT id, name FROM users WHERE active = ?", "params": [true]}' ~~~ ### Response ~~~json { "success": true, "errors": [], "messages": [], "result": [{ "success": true, "results": [{ "id": 1, "name": "Ada" }], "meta": { "duration": 1 } }] } ~~~ ### Behavior and errors - This write-authorized operation preserves the D1 query response envelope. It can read or change data and schema. - D1 evaluates the SQL. This first surface exposes query only, not batch or raw-query variants. - The query endpoint also permits direct access to `_interfold_migrations`; changing that ledger can break migration tracking. ### Related interfaces - **CLI:** `interfold db query --site "SELECT id FROM users"` - **MCP:** `query_database` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## List migration history List successful migration receipts stored in the database. **`GET`** `/v0/sites/:siteId/databases/:databaseId/migrations` - **API key permission:** Read-only or Read/write ### Parameters - `siteId` — site UUID. - `databaseId` — database UUID. ### Request ~~~sh curl \ "https://api.interfold.dev/v0/sites//databases//migrations" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "database": { "id": "", "status": "READY" }, "applied": [{ "id": 1, "name": "0001_create_users.sql", "checksum": "", "appliedAt": "2026-09-24 12:00:00", "sourceAvailable": true }] } ~~~ ### Related interfaces - **CLI:** `interfold db migrations list --site ` - **MCP:** `list_database_migrations` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Get a migration Get one successful receipt and its stored SQL. **`GET`** `/v0/sites/:siteId/databases/:databaseId/migrations/:migrationName` - **API key permission:** Read-only or Read/write ### Parameters - `siteId` — site UUID. - `databaseId` — database UUID. - `migrationName` — exact numbered migration filename. ### Request ~~~sh curl \ "https://api.interfold.dev/v0/sites//databases//migrations/:migrationName" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "migration": { "name": "0001_create_users.sql", "checksum": "", "sourceAvailable": true, "sql": "CREATE TABLE users (id TEXT PRIMARY KEY);" } } ~~~ ### Related interfaces - **MCP:** `get_database_migration` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Apply one migration Apply one migration without supplying prior local files. **`POST`** `/v0/sites/:siteId/databases/:databaseId/migrations` - **API key permission:** Read/write ### Parameters - `siteId` — active site UUID. - `databaseId` — database UUID. - `name` — numbered migration filename. - `sql` — exact migration SQL. - `confirm` — required literal `true`. ### Request ~~~sh curl -X POST \ "https://api.interfold.dev/v0/sites//databases//migrations" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "name": "0002_add_email.sql", "sql": "ALTER TABLE users ADD COLUMN email TEXT;", "confirm": true}' ~~~ ### Response ~~~json { "migration": { "name": "0002_add_email.sql", "sql": "ALTER TABLE users ADD COLUMN email TEXT;" }, "alreadyApplied": false } ~~~ ### Related interfaces - **MCP:** `apply_database_migration` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Apply migrations Validate an ordered migration prefix and apply its pending migrations. **`POST`** `/v0/sites/:siteId/databases/:databaseId/migrations/apply` - **API key permission:** Read/write ### Parameters - `siteId` — active site UUID. - `databaseId` — database UUID. - `migrations` — exact ordered migration prefix. - `confirm` — required literal `true`. ### Request ~~~sh curl -X POST \ "https://api.interfold.dev/v0/sites//databases//migrations/apply" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "migrations": [{ "name": "0001_create_users.sql", "sql": "CREATE TABLE users (id TEXT PRIMARY KEY);" }], "confirm": true}' ~~~ ### Response ~~~json { "appliedNames": ["0001_create_users.sql"], "nextAction": "NONE", "nextCommand": "" } ~~~ ### Behavior and errors - The operation validates provider history before applying. History conflicts, active leases, and ambiguous provider failures return structured recovery details. ### Related interfaces - **CLI:** `interfold db migrations apply --site --confirm` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Create a deletion challenge Create the short-lived code required for permanent deletion. **`POST`** `/v0/sites/:siteId/databases/:databaseId/deletion-challenges` - **API key permission:** Read/write ### Parameters - `siteId` — active site UUID. - `databaseId` — database UUID. ### Request ~~~sh curl -X POST \ "https://api.interfold.dev/v0/sites//databases//deletion-challenges" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "confirmationCode": "DELETE-1A2B3C4D", "expiresAt": "2026-09-20T12:10:00.000Z", "nextCommand": "interfold db delete --site --confirm DELETE-1A2B3C4D" } ~~~ ### Related interfaces - **CLI:** `interfold db delete --site ` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Delete a database Permanently delete the site database using a valid challenge. **`DELETE`** `/v0/sites/:siteId/databases/:databaseId` - **API key permission:** Read/write ### Parameters - `siteId` — active site UUID. - `databaseId` — database UUID. - `confirmationCode` — current `DELETE-XXXXXXXX` challenge. ### Request ~~~sh curl -X DELETE \ "https://api.interfold.dev/v0/sites//databases/" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "confirmationCode": "DELETE-1A2B3C4D"}' ~~~ ### Response ~~~json { "deleted": true, "databaseId": "" } ~~~ ### Behavior and errors - Deletion is permanent. Export important data first. ### Related interfaces - **CLI:** `interfold db delete --site --confirm DELETE-1A2B3C4D` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## List database exports List retained export records, including terminal failures. **`GET`** `/v0/sites/:siteId/databases/:databaseId/exports` - **API key permission:** Read-only or Read/write ### Parameters - `siteId` — site UUID. - `databaseId` — database UUID. - `limit` and `offset` — standard pagination fields. ### Request ~~~sh curl \ "https://api.interfold.dev/v0/sites//databases//exports" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "exports": [], "pagination": { "hasMore": false, "nextOffset": null } } ~~~ ### Behavior and errors - Export access is limited to account administrators and API keys. See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Create a database export Start a portable SQL export. **`POST`** `/v0/sites/:siteId/databases/:databaseId/exports` - **API key permission:** Read/write ### Parameters - `siteId` — site UUID; archived sites are allowed. - `databaseId` — database UUID. ### Request ~~~sh curl -X POST \ "https://api.interfold.dev/v0/sites//databases//exports" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "export": { "id": "", "status": "PROCESSING" } } ~~~ ### Behavior and errors - Account members cannot start exports; use an admin or API key. See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Reconcile a database export Refresh a processing export until it is complete or failed. **`POST`** `/v0/sites/:siteId/databases/:databaseId/exports/:exportId/reconcile` - **API key permission:** Read/write ### Parameters - `siteId` — site UUID. - `databaseId` — database UUID. - `exportId` — export UUID. ### Request ~~~sh curl -X POST \ "https://api.interfold.dev/v0/sites//databases//exports//reconcile" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "export": { "id": "", "status": "COMPLETE", "downloadUrl": "" } } ~~~ See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. ## Shared behavior All operations use the [API authentication](/api-reference/authentication), [error](/api-reference/errors), and [rate-limit](/api-reference/rate-limits) contracts. List operations use [standard pagination](/api-reference/pagination) unless the operation says otherwise. --- # Secrets Manage site runtime secrets and audit explicit value retrievals. | Method | Operation | Path | | --- | --- | --- | | **`GET`** | [List secrets](#list-secrets) | `/v0/sites/:siteId/secrets` | | **`GET`** | [Get a secret value](#get-a-secret-value) | `/v0/sites/:siteId/secrets/:name` | | **`GET`** | [List secret access logs](#list-secret-access-logs) | `/v0/sites/:siteId/secret_access_logs` | | **`POST`** | [Create a secret](#create-a-secret) | `/v0/sites/:siteId/secrets` | | **`POST`** | [Update a secret](#update-a-secret) | `/v0/sites/:siteId/secrets/:name` | | **`DELETE`** | [Delete a secret](#delete-a-secret) | `/v0/sites/:siteId/secrets/:name` | ## List secrets List secret names and metadata without values. **`GET`** `/v0/sites/:siteId/secrets` - **API key permission:** Read-only or Read/write ### Parameters - `siteId` — site UUID. - `limit` and `offset` — standard pagination fields. ### Request ~~~sh curl \ "https://api.interfold.dev/v0/sites//secrets" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "secrets": [{ "name": "API_TOKEN", "updatedAt": "2026-09-20T12:00:00.000Z" }], "pagination": { "hasMore": false, "nextOffset": null } } ~~~ ### Related interfaces - **CLI:** `interfold secrets list --site ` - **MCP:** `list_secrets` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Get a secret value Retrieve a secret value and record an access-log entry. **`GET`** `/v0/sites/:siteId/secrets/:name` - **API key permission:** Read-only or Read/write ### Parameters - `siteId` — site UUID. - `name` — secret name. ### Request ~~~sh curl \ "https://api.interfold.dev/v0/sites//secrets/" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "secret": { "name": "API_TOKEN", "value": "" } } ~~~ ### Behavior and errors - Read-only keys can retrieve values. Treat them as sensitive credentials. - Prefer metadata listing when you only need to verify that a secret exists. - MCP intentionally has no secret-value tool. ### Related interfaces - **CLI:** `interfold secrets get API_TOKEN --site ` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## List secret access logs List audited dashboard, CLI, and API secret-value retrievals. **`GET`** `/v0/sites/:siteId/secret_access_logs` - **API key permission:** Read-only or Read/write ### Parameters - `siteId` — site UUID. - `limit` and `offset` — standard pagination fields. ### Request ~~~sh curl \ "https://api.interfold.dev/v0/sites//secret_access_logs" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "accessLogs": [], "pagination": { "hasMore": false, "nextOffset": null } } ~~~ See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Create a secret Create or replace a named secret. **`POST`** `/v0/sites/:siteId/secrets` - **API key permission:** Read/write ### Parameters - `siteId` — site UUID. - `name` — secret name. - `value` — secret value. ### Request ~~~sh curl -X POST \ "https://api.interfold.dev/v0/sites//secrets" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "name": "API_TOKEN", "value": ""}' ~~~ ### Response ~~~json { "secret": { "name": "API_TOKEN", "updatedAt": "2026-09-20T12:00:00.000Z" } } ~~~ ### Behavior and errors - Responses never echo the supplied value. ### Related interfaces - **CLI:** `printf %s "$API_TOKEN" | interfold secrets set API_TOKEN --site ` - **MCP:** `set_secret` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Update a secret Replace a named secret value. **`POST`** `/v0/sites/:siteId/secrets/:name` - **API key permission:** Read/write ### Parameters - `siteId` — site UUID. - `name` — secret name. - `value` — replacement value. ### Request ~~~sh curl -X POST \ "https://api.interfold.dev/v0/sites//secrets/" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" \ -H "Content-Type: application/json" \ --data '{ "value": ""}' ~~~ ### Response ~~~json { "secret": { "name": "API_TOKEN", "updatedAt": "2026-09-20T12:00:00.000Z" } } ~~~ ### Behavior and errors - Responses never echo the supplied value. ### Related interfaces - **CLI:** `printf %s "$API_TOKEN" | interfold secrets set API_TOKEN --site ` - **MCP:** `set_secret` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. --- ## Delete a secret Delete a named secret. **`DELETE`** `/v0/sites/:siteId/secrets/:name` - **API key permission:** Read/write ### Parameters - `siteId` — site UUID. - `name` — secret name. ### Request ~~~sh curl -X DELETE \ "https://api.interfold.dev/v0/sites//secrets/" \ -H "Authorization: Bearer $INTERFOLD_API_KEY" ~~~ ### Response ~~~json { "deleted": true } ~~~ ### Behavior and errors - Existing functions or cron jobs may fail until the secret is restored. ### Related interfaces - **CLI:** `interfold secrets rm API_TOKEN --site ` - **MCP:** `delete_secret` See [Errors](/api-reference/errors) for the standard error envelope and [Authentication](/api-reference/authentication) for API key handling. ## Shared behavior All operations use the [API authentication](/api-reference/authentication), [error](/api-reference/errors), and [rate-limit](/api-reference/rate-limits) contracts. List operations use [standard pagination](/api-reference/pagination) unless the operation says otherwise. --- # CLI The `interfold` CLI is the primary local interface for people and coding agents. It manages credentials, account and project context, sites, buckets, files, databases, secrets, and agent skills. All commands print JSON to stdout so scripts and agents can parse results without scraping human-oriented output. ## Install and upgrade ```sh curl -fsSL https://downloads.interfold.dev/install.sh | bash interfold version interfold upgrade ``` Self-upgrade supports CLIs installed by the official installer at `~/.interfold/bin/interfold`. ## Command groups - [Authentication](/cli/authentication) - [Accounts & projects](/cli/accounts-projects) - [Sites & buckets](/cli/sites-buckets) - [Files](/cli/files) - [Databases](/cli/databases) - [Secrets](/cli/secrets) - [Agent skills](/cli/skills) ## Global flags | Flag | Description | | ----------------- | --------------------------------------------------------------- | | `--api-key ` | Authenticate with an explicit API key for one command. | | `--account ` | Select the saved credential for one command. | | `--cwd ` | Start project discovery and relative file resolution at a path. | The CLI also reads `INTERFOLD_API_KEY`, `INTERFOLD_ACCOUNT_ID`, and `INTERFOLD_SITE_ID`. ## Choose CLI, REST, or MCP Use the CLI for local development, shell automation, safe credential storage, content-type detection, and project-linked site context. Use the [REST API](/api-reference) for service integrations. Use [MCP](/mcp) when an agent client can connect to a remote MCP server and should work through explicit tools. --- # CLI authentication Browser login stores an account credential locally without putting the key in project files or shell history. ## Log in ```sh interfold login ``` Keep the command running while you approve the browser session. The CLI finishes the credential exchange in the same terminal. | Flag | Description | | --------------- | ------------------------------------------------- | | `--no-browser` | Print the login URL instead of opening a browser. | | `--token ` | Store an API key non-interactively. | | `--json` | Print JSON output. | ## Check the active credential ```sh interfold whoami interfold auth status ``` `auth status` reports whether authentication came from an explicit flag, environment variable, saved login, or project account context. Use it when an environment key appears to shadow a browser login. Authentication precedence is: 1. `--api-key` 2. `INTERFOLD_API_KEY` 3. Saved login ## Log out ```sh interfold logout interfold logout --account interfold logout --all ``` Logging out does not remove `INTERFOLD_API_KEY` from the shell or CI environment. ## Credential safety Never paste API keys into chat or commit them to a project. The CLI stores account-keyed credentials outside the project with restrictive file permissions. --- # CLI accounts & projects Use account commands for local credential selection and project links for a stable account and Site context inside a checkout. ## Accounts ```sh interfold accounts list interfold accounts current interfold accounts use ``` Account resolution is: 1. `--account` 2. `INTERFOLD_ACCOUNT_ID` 3. Nearest project link 4. `defaultAccountId` There is no default Site. ## Link a project ```sh interfold link --account --site interfold link status interfold --cwd unlink ``` The link is stored in `.interfold/project.json` and contains account and Site IDs, never credentials. Commands search from `--cwd` or the process working directory through its parents. The nearest link wins. `unlink` removes only a link in the selected working directory. It does not silently remove an ancestor link. Site resolution is: 1. `--site` 2. `INTERFOLD_SITE_ID` 3. Nearest project link ## Local config ```sh interfold config get interfold config get defaultAccountId interfold config set defaultAccountId ``` Authentication keys are not config values. Use `interfold login`, `--api-key`, or `INTERFOLD_API_KEY`. --- # CLI sites & buckets Sites provide hosted identity and access. Buckets own files independently from the sites attached to them. ## Sites ```sh interfold sites list --status ACTIVE interfold sites get interfold sites create --name "My Site" --access PRIVATE interfold sites update --access PUBLIC interfold sites update --reconcile ``` `sites list` accepts `--account`, `--status`, `--limit`, and `--offset`. `sites create` accepts `--name`, `--access`, `--subdomain`, `--account`, and `--bucket`. List commands retain their resource name (`sites` or `buckets`) and include `pagination`. Use `pagination.nextOffset` for the next `--offset`; it is `null` on the final page. Use `sites get` to read the actual subdomain before constructing a hosted URL. Do not guess it from the Site name. `--reconcile` reseeds and retries durable per-path function and cron desired state. Ordinary executable file writes already reconcile immediately; `--reconcile` is the manual repair path for attachment, reactivation, or an exception that exhausted automatic retries. Inspect the returned status and deployment results before claiming the runtime is ready. ## Buckets ```sh interfold buckets list interfold buckets create --name "My files" interfold buckets get interfold buckets update --name "Production files" ``` Attach an existing bucket during Site creation: ```sh interfold sites create --name "My Site" --bucket ``` Omitting `--bucket` creates storage automatically. ## Access A Site is `PUBLIC` or `PRIVATE`. Site access controls anonymous `/web/` files; there are no per-file exposure overrides. Deployed `/api/` runtimes are anonymously callable for either setting, so handlers must enforce their own authorization. Bucket and Files API access always requires account authentication. --- # CLI files File commands are path-first and bucket-scoped. Select a bucket directly or resolve it through an attached Site. ## Commands ```sh interfold files ls /data --bucket interfold files stat /web/index.html --site interfold files cat /web/index.html --site interfold files get /web/index.html ./index.html --site interfold files put ./index.html /web/index.html --site \ --content-type 'text/html; charset=utf-8' interfold files rm /web/old.html --site interfold files history ls interfold files history cat interfold files history get ./old-copy.bin interfold files history restore ``` | Command | Description | | ------- | --------------------------------------------------- | | `ls` | List file metadata, optionally below a path prefix. | | `stat` | Print metadata without downloading content. | | `cat` | Write raw content to stdout. | | `get` | Download content to a local path. | | `put` | Create or replace a file. | | `rm` | Delete a file. | | `history ls` | List recent versions by stable file ID. | | `history cat` | Print a historical version. | | `history get` | Download a historical version atomically to a local path. | | `history restore` | Make historical content current as a new version. | `ls` prints `files` plus `pagination`. Pass `--offset` from `pagination.nextOffset` to continue a listing. Each successful `put` returns a stable `fileId` and a new `versionId`. Use `--if-match ` on `put` to reject a stale write with HTTP 409. The flag is optional for older scripts. A restore always requires the current version ID and keeps the file's current path and permissions. ## Selecting storage Use `--bucket ` for direct storage access. As a convenience, use `--site `, `--subdomain `, a project link, or a hosted URL when the bucket is attached to a Site. File and Bucket API access always requires account authentication. Attaching a Site only maps `/web/` files to hosted static URLs; it does not expose source, cron, data, database or migration assets, or arbitrary bucket objects. ```sh interfold files get https://example.interfold.site/assets/logo.png ./logo.png ``` ## Live effects Writing an attached `/web/*` file affects the hosted Site immediately. Writing `/api/*.ts` or `/cron/*.ts` also starts runtime deployment. Inspect the returned `deployment` object. It identifies the durable request with `deploymentId`, `generation`, `desiredState`, and `status`. The API reconciles the saved generation immediately, so a normal write returns `READY` without waiting for a background job. A `FAILED` result means the file and requested runtime state were saved, but promotion did not finish. The recovery worker retries that exact generation on its next once-per-minute pass. Verify the runtime URL or scheduled result before depending on it. Deleting function or cron source records `desiredState: ABSENT` before removing or pausing its deployed runtime. Failed cleanup is retried the same way. --- # CLI databases Manage the current Site database and keep schema changes in numbered SQL files under the project-root `migrations/` directory. ## Create a database ```sh interfold db create --site ``` ## Query a database Forward generic D1 SQL with a write-authorized API key. Queries can read or change data and schema, so use placeholders for values and review writes carefully: ```sh interfold db query --site 'SELECT id, name FROM users WHERE active = ?' --params '[true]' interfold db query --site 'UPDATE users SET active = ? WHERE id = ?' --params '[false, 42]' ``` The command prints the D1-style response envelope. It accepts one SQL string and an optional JSON parameter array; D1 evaluates SQL errors. This is a write-capability command even for a `SELECT` statement. ## Create and inspect migrations ```sh interfold db migrations create create_users interfold db migrations list --site ``` `list` returns successful cloud migration receipts without reading local migration files. `apply` compares the ordered local migration prefix with provider history before applying pending files. When an API operation fails, the CLI reads the REST error envelope and carries documented recovery metadata from `error.details` into its structured command error. It keeps REST transport details separate from its own JSON stderr output. ## Apply migrations ```sh interfold db migrations apply --site --confirm ``` Always run `list` immediately before `apply`. An interrupted request can be recovered by listing again; do not guess whether the provider committed a migration. ## Delete permanently Deletion is a two-step operation: ```sh interfold db delete --site interfold db delete --site --confirm DELETE-XXXXXXXX ``` The first command creates a short-lived challenge and changes nothing. Export important data before confirming deletion. See [Databases](/databases) for direct-query behavior, runtime queries, and migration-file rules. --- # CLI secrets Site secrets are named runtime values read through `ctx.secrets`. ## List metadata ```sh interfold secrets list --site ``` Prefer listing when you only need to verify that a secret exists. ## Set a value Pipe values through stdin so they do not land in shell history: ```sh printf '%s' "$OPENAI_API_KEY" | interfold secrets set OPENAI_API_KEY --site ``` `set` creates or replaces the named secret. ## Retrieve a value ```sh interfold secrets get OPENAI_API_KEY --site interfold secrets get OPENAI_API_KEY --site --raw ``` Retrieval reveals sensitive data and creates an audit-log entry. Use it only when the task explicitly requires the value. ## Delete ```sh interfold secrets rm OPENAI_API_KEY --site ``` Existing functions or cron jobs may fail until a deleted secret is restored. --- # CLI agent skills Install the Interfold skill so supported coding agents know the current publishing, authentication, database, and secret-safety workflows. ## Inspect installation ```sh interfold skills status ``` The command reports supported agent locations and installed state. ## Install or update ```sh interfold skills install ``` Use `--dry-run` to preview changes when supported: ```sh interfold skills install --dry-run ``` The skill teaches an agent to use the CLI, select a Site explicitly, keep credentials out of project files, verify live URLs, and report exactly what was published. --- # MCP Interfold's MCP server lets compatible agents work with sites, buckets, files, functions, databases, migrations, and secret metadata through explicit tools. It uses Streamable HTTP: ```text https://api.interfold.dev/mcp ``` MCP is an agent-facing adapter over the Interfold API. It uses the same account-scoped API keys and permission checks; it does not create a separate MCP identity or duplicate business logic. ## Start here - [Connect a client](/mcp/connect) - [Tool reference](/mcp/tools) - [Permissions & safety](/mcp/safety) ## Choose MCP, CLI, or REST Use MCP when the client supports remote tools and should reason through explicit schemas and approvals. Use the [CLI](/cli) for local files, project context, credential storage, and shell workflows. Use the [REST API](/api-reference) for services and direct HTTP integrations. ## Account and resource context Every tool uses the account authorized by the API key. Site- and bucket-scoped tools require explicit IDs; there is no hidden selected Site. Discover resources before mutating them. File writes can change a live Site immediately. Read [Permissions & safety](/mcp/safety) before enabling write tools. --- # Connect an MCP client Connect to Interfold with Streamable HTTP and an account-scoped API key. ## Server ```text https://api.interfold.dev/mcp ``` ## Setup 1. Create an API key in the dashboard under **API Keys**. 2. Choose **Read-only** to explore or **Read/write** to change resources. 3. Add a Streamable HTTP MCP server using the URL above. 4. Configure the client to send `Authorization: Bearer `. 5. Reconnect, then ask the client to list Interfold sites. When a client asks for a bearer token, enter the raw key without the `Bearer ` prefix. When it asks for a bearer-token environment variable, enter the variable name rather than the value. ## Codex configuration ```toml [mcp_servers.interfold] url = "https://api.interfold.dev/mcp" bearer_token_env_var = "INTERFOLD_API_KEY" default_tools_approval_mode = "writes" tool_timeout_sec = 360 ``` The `INTERFOLD_API_KEY` value must exist in the environment of the Codex process. Keep the value out of config files, project files, and chat. On macOS, this prompts without putting the key in shell history: ```zsh read -rs "interfold_token?Paste your Interfold API key: " printf '\n' launchctl setenv INTERFOLD_API_KEY "$interfold_token" unset interfold_token ``` Fully quit and reopen the app after setting it. Repeat after logging out or restarting macOS. ## Hosted clients A hosted client cannot read local environment variables or local Codex config. Interfold currently uses API-key bearer authentication and does not provide OAuth discovery for hosted ChatGPT connections. Use a client that supports a private bearer token. ## Verify Ask the client to list tools, then call `list_sites`. A missing or invalid key returns an authentication error; a Read-only key can call read tools but not write tools. --- # MCP tool reference Interfold MCP tools map to the normal REST resources. Tool responses preserve the API's structured JSON. List tools accept optional `limit` and `offset` and return their resource-specific array plus `pagination`; continue with `pagination.nextOffset` while `pagination.hasMore` is true. ## Sites | Tool | Effect | | ------------- | ----------------------------------------------------- | | `list_sites` | List sites in the authorized account. | | `create_site` | Create a Site, optionally with an existing bucket. | | `get_site` | Read one Site and reconciliation state. | | `update_site` | Change name, access, status, or retry reconciliation. | See [Sites API](/api-reference/sites). ## Buckets | Tool | Effect | | --------------- | --------------------------- | | `list_buckets` | List account-owned buckets. | | `create_bucket` | Create storage. | | `get_bucket` | Read bucket metadata. | | `update_bucket` | Rename a bucket. | See [Buckets API](/api-reference/buckets). ## Files | Tool | Effect | | ------------- | --------------------------------------------- | | `list_files` | List files or find an exact path. | | `read_file` | Read text content and metadata up to 256 KiB. | | `write_file` | Create or replace a complete text file. | | `delete_file` | Delete a file. | | `list_file_versions` | List recent revisions by stable `file_id`. | | `read_file_version` | Read historical text content up to 256 KiB. | | `restore_file_version` | Restore content with an expected current version ID. | Path-based file tools take an explicit `bucket_id`; history tools take the stable `file_id` returned by file metadata. Get a bucket ID from `get_site` or `list_buckets`. The 256 KiB text limit protects agent context and is an Interfold MCP client policy, not an MCP protocol limit. Download larger or binary revisions through the [Files API](/api-reference/files) or CLI. `write_file` accepts optional `expected_current_version_id` for conflict protection and returns the saved version ID. A restore creates another version; it does not change the file path or access rules. ## Functions | Tool | Effect | | ---------------- | ------------------------------------------- | | `list_functions` | List deployed functions and current status. | Deploy by writing source to `/api/.ts`; there is no separate MCP deploy tool. See [Functions API](/api-reference/functions). ## Databases | Tool | Effect | | -------------------------- | ----------------------------------------------- | | `list_databases` | Inspect the site database and binding state. | | `create_database` | Create or resume database provisioning. | | `list_database_migrations` | List successful cloud migration metadata. | | `get_database_migration` | Read one successful receipt and its stored SQL. | | `apply_database_migration` | Apply one migration with explicit confirmation. | See [Databases API](/api-reference/databases). ## Secrets | Tool | Effect | | --------------- | --------------------------------------- | | `list_secrets` | List names and metadata without values. | | `set_secret` | Create or replace a secret. | | `delete_secret` | Delete a secret. | There is intentionally no `get_secret` tool. See [Secrets API](/api-reference/secrets). --- # MCP permissions & safety MCP uses the same Read-only and Read/write API-key permissions as REST. Each tool operation is checked before it runs. ## Read and write boundaries Read-only keys can inspect sites, buckets, files, functions, databases, migration status, and secret metadata. They cannot create, update, apply, or delete resources. Use write approvals for mutating tools. Inspect current state before a change and verify the affected resource afterward. ## Live file writes `write_file` replaces the complete file and can affect an attached Site immediately. - `/web/*` changes hosted content. - `/api/*.ts` starts function deployment. - `/cron/*.ts` starts scheduled-handler deployment. There is no Site-level draft or deploy tool. Inspect the returned deployment status and verify the hosted URL or runtime before claiming success. Deleting function or cron source also removes or pauses its deployed runtime. ## Secrets `list_secrets` returns names and metadata, never values. There is no `get_secret` tool. Do not place secrets in tool arguments other than the value field of an explicitly approved `set_secret` call. ## Database migrations Cloud-first agents can use `list_database_migrations`, `get_database_migration`, and `apply_database_migration`. List and get expose successful migration resources; get includes exact SQL when it was recorded. Apply accepts one filename and SQL body with `confirm: true`; it does not require previous local files or a preflight token. The MCP confirmation binds the exact SQL. A Read-only key can inspect migrations but cannot apply them. ## Recovery When an underlying REST call fails, MCP reports a protocol-level tool error and preserves the REST generic code, message, and structured recovery metadata from `error.details`. Preserve fields such as `retryable`, `nextAction`, `migrationName`, and lease expiry. Re-read state after an ambiguous failure instead of assuming a write did or did not happen. --- # Agent guide Interfold is built to be driven by coding agents. This page is the reference for an agent operating Interfold on a user's behalf: the tools, the safe defaults, and the conventions that keep publishes correct and credentials protected. If you are a human, this page still doubles as a concise operating checklist. ## Machine-readable docs Every page on this site is available as raw Markdown at a predictable URL, plus two aggregate files following the [llms.txt](https://llmstxt.org) convention: - **[/llms.txt](/llms.txt)** — an index of every doc with one-line descriptions and links. Fetch this first to orient. - **[/llms-full.txt](/llms-full.txt)** — the entire documentation set concatenated into a single file. Fetch once to load everything. - **Raw per page** — append the slug to `/raw/`. This page is at `/raw/agents`; the CLI reference is at `/raw/cli`; and so on. All three are served as plain text so you can fetch and parse them directly: ```sh curl https://docs.interfold.site/llms.txt curl https://docs.interfold.site/raw/cli ``` ## Choose the CLI or MCP The browser agent also exposes `list_buckets`, `get_bucket`, `create_bucket`, and `update_bucket` (rename). Bucket reads run automatically; writes follow the agent's approval flow. For a hosted app or page, its default is `create_site`, which creates a bucket automatically. It can attach an existing unattached bucket with `create_site.bucket_id`. Its file-editing tools remain site-oriented. The `interfold` CLI is the primary interface for local coding agents. It stores credentials, resolves site context, and detects content types. Agents with a remote MCP client can instead connect to the [Interfold MCP server](/mcp) using an API key. Prefer these interfaces over raw [REST API](/api-reference) calls unless the task needs an operation they do not expose. Install the skill so your agent has the full operating guide locally: ```sh interfold skills install ``` ## Start CLI tasks with readiness checks ```sh interfold whoami # confirm authentication interfold config get # see defaultAccountId interfold link status # see the nearest local account/site binding ``` If authentication is missing or expired, keep the current agent task alive while the user approves a browser login: 1. Run `interfold login` yourself in the current agent terminal. 2. Tell the user to sign in and approve Interfold CLI in the browser. Leave the command running. 3. Wait for the command to finish, verify with `interfold auth status`, and continue the original website task. If the agent runtime cannot keep a terminal process alive, ask the user to run `interfold login` and re-check authentication when they return. Never ask the user to paste an API key or share a credential file, and never write credentials into project files — the CLI owns credential storage. ### If your agent paused during login Paste this into the same agent conversation after approving the browser login: ```text I approved Interfold login. Please re-check `interfold auth status` and continue the website task from where you left off. Do not ask me to log in again or paste credentials. ``` ## Choose a site deliberately Select a site before every site-scoped command. Reuse an existing active site for updates or standalone pages; create a new site only for a genuinely new project or an explicit request. ```sh interfold sites list --status ACTIVE --limit 50 interfold sites get # read the real subdomain before building URLs ``` When reusing a site, preserve `/web/index.html` unless the user clearly wants the homepage replaced. For a new standalone page, use a workspace path like `/web/demo.html`, hosted at `/demo.html`. For MCP, call `list_sites` and `get_site` instead. Pass the explicit site ID to each site-scoped tool. MCP `write_file` changes the live site immediately; it does not stage changes for a later deployment. The site agent can list recent file revisions, read a historical text revision, and restore one with approval. The restore creates a new current revision and requires the current version ID returned by `get_site_file` or the file list. ## Publish, then verify Never report a page as live without checking the hosted URL. ```sh interfold files put ./index.html /web/index.html --site --content-type 'text/html; charset=utf-8' interfold sites get curl -I https://.interfold.site/index.html curl -I https://.interfold.site/ # for the homepage, verify root too ``` If verification fails, report the failed command and the error text. Do not claim success. ## Access defaults - Site access is `PUBLIC` or `PRIVATE`. If the user expects anonymous visitors, the site must be `PUBLIC`. - Site access gates anonymous `/web/` files only. Every deployed `/api/` runtime is anonymously callable; its handler must own any authorization. - Bucket and Files APIs, function source, cron source, data, database state, migration assets, and other stored objects remain account-private. Full model in [Sites & access](/sites). ## Handle secrets safely - Set secrets via stdin: `printf '%s' "$VALUE" | interfold secrets set NAME --site `. - Verify existence with `secrets list`, not `secrets get`. - Never print secret values in summaries or logs. ## Report results precisely After a successful task, state: - the site id, - the paths you changed, - the live URL, - the verification you performed. Keep it short and factual. Don't mention local credential paths unless a troubleshooting step requires it. --- Deeper references: [CLI](/cli) · [MCP](/mcp) · [API](/api-reference) · [Functions](/functions) · [Cron Jobs](/cron-jobs) · [Databases](/databases) · [Data files](/data-storage) · [Secrets](/secrets) Hosted `/web/` files follow Site-wide access. Per-file access overrides are not supported; function handlers own their authorization. --- # Changelog Product updates for Interfold. New entries will appear here as features ship. ## October 6, 2026 — Model calls from site functions Functions and Cron Jobs can now call OpenAI models with `ctx.llm.messages.create`. Send text messages to Luna or GPT-6.1 Sol without setting up an API key. Usage shares the site's owning account allowance with the browser agent. [Read the model calls guide](/functions#model-calls). ## October 1, 2026 — File version history Overwriting a file will keep its recent revisions while publishing the new content immediately. Authenticated account members will be able to list and read historical revisions; editors will be able to restore one as a new current revision. File writes can include an expected current version to prevent stale changes. Restore retains the current path and access rules. This change does not add site-wide or database rollback. ## September 28, 2026 — Browser agent dictation You can now dictate messages to the browser agent. Use the microphone in the chat composer to record your voice, then review and edit the transcribed text before sending. Press Escape to cancel dictation and keep your existing draft. ## August 30, 2026 — Cron Jobs for all accounts Cron Jobs are now available to every Interfold account. The limited preview has ended; add a TypeScript file in `/cron/*` and give it a UTC schedule. [Read the Cron Jobs documentation](/cron-jobs). ## August 8, 2026 — Databases Every Interfold site can now have its own SQL database. Create it with the CLI, manage its schema with migrations, and query it from Functions through `ctx.db`. [Read the Databases documentation](/databases). ## July 26, 2026 — Cron Jobs Cron Jobs are available in limited preview for approved Interfold accounts. Add a TypeScript file in `/cron/*` and give it a UTC schedule. It runs in the same isolated environment as a site function. - Use a five-part schedule. Jobs can run no more often than every five minutes. - Each run has a stable ID, so you can safely repeat calls to external services. - Jobs can use the same site data and secrets as Functions. [Read the Cron Jobs documentation](/cron-jobs). ## July 14, 2026 — Function request cookies Site functions can now receive cookies from the browser request that calls them. This lets you build signed-in experiences behind your site's `/api/*` routes without forwarding cookies yourself. [Read the Functions documentation](/functions). ## July 13, 2026 — CLI self-updates The Interfold CLI can now upgrade itself directly. Use `interfold upgrade` to install the latest release without re-running the installer. [Read the CLI reference](/cli). ## July 6, 2026 — Account-wide API rate limits API keys now share one rate limit per account. When you reach the limit, the API returns `429` and retry headers. The limit applies across all clients that use the account. [Read the API reference](/api-reference). ## June 28, 2026 — Browser login for the CLI `interfold login` now opens a browser to approve a CLI session. For headless environments, `interfold login --no-browser` prints the approval URL instead. [Read the CLI reference](/cli). ## June 26, 2026 — Path-based files and function data You can now manage files directly by site path. List, inspect, download, upload, and remove files without looking up a file ID first. Functions can also use `/data/*` to save text, JSON, and JSONL. [Read the CLI reference](/cli) · [Read the Data files documentation](/data-storage). ## June 21, 2026 — Interfold Functions Interfold Functions let you add server-side TypeScript at `/api/*`. Upload a function source file to create a live endpoint. You do not need to operate a server. Functions can use the same site data and secrets as the rest of your site. [Read the Functions documentation](/functions). ## June 14, 2026 — Private site access gates Protected site files now show a clear access page. Visitors who are not signed in see a sign-in prompt. Signed-in visitors without permission see a no-access page. [Read the Sites & access documentation](/sites). ## June 6, 2026 — The first publish workflow You can now create a site from the CLI, upload an HTML file, and publish it on a live Interfold subdomain. This simple loop remains at the center of the platform. ## June 5, 2026 — CLI installer The Interfold CLI now has a hosted installer. Use it to set up the command-line workflow on a new machine. [Read the CLI reference](/cli).