# CLI, publishing, and keys

Last updated: 2026-07-12

Web page: https://fillo.so/docs/cli
Docs overview: https://fillo.so/docs.md
Quickstart: https://fillo.so/docs/embed.md
Agent setup: https://fillo.so/agents.md

Use the CLI to sync and publish forms, and choose the right key for each command.

## Choose the credential by workflow

| Workflow | Credential | Lifecycle |
| --- | --- | --- |
| Render a published form by formId or slug | No key | The dashboard's published version loads and accepts responses. |
| Sync a code-defined form from browser or app code | `pk_` publishable key | Claimed workspaces stage changes for human review before publication. |
| Push reviewed JSON from a terminal | Private CLI token from `fillo login` | Publishes directly by default; `--draft` takes the form offline as a draft. |
| Connect Zapier | Private API token | Authorizes Zapier form discovery and response hook subscriptions. |

> **Public and private keys are not interchangeable:** A `pk_` key is safe to expose and can sync schemas, but cannot manage the workspace. CLI and Zapier API tokens are private management credentials; keep them out of client bundles and logs.

## Connect the CLI

Use login for an existing Fillo account. It opens a browser, asks you to choose the exact workspace, and stores the resulting CLI token in the local Fillo config.

Use init only when you need a new capped preview workspace. It requires an email so Fillo can send the durable claim link; do not create a second workspace when an existing team workspace is the intended target.

```bash
# Existing account and workspace
npx @usefillo/cli@latest login
npx @usefillo/cli@latest whoami

# New preview workspace only
npx @usefillo/cli@latest init --email you@company.com
```

## Push a reviewed schema

`push` accepts JSON by default. Give the form a stable handle so later pushes update the same Fillo form and preserve its `formId`, hosted slug, existing responses, storage selection, and separate webhook/integration records. The incoming schema replaces the stored schema wholesale, including schema-backed settings such as notification and receipt controls.

- A normal authenticated push replaces the live schema for that stable handle and clears an older staged revision. Review the JSON before running it against production.
- `--draft` sets the form status to draft; it is not a side-by-side draft revision. Publish it later from the dashboard.
- A `file_upload` field still needs a connected storage destination before the CLI can publish the form.
- JavaScript schema files require the explicit `--allow-code` flag because loading them executes local code. Prefer JSON for reviewable automation.

```bash
# Creates or updates and publishes immediately after login
npx @usefillo/cli@latest push form.json --handle onboarding

# Creates a draft, or takes an existing live form offline as a draft
npx @usefillo/cli@latest push form.json --handle onboarding --draft

npx @usefillo/cli@latest list
```

## Sync safely with a publishable key

1. **Copy the workspace key:** Open **Settings → Developers → Form sync**. Put the `pk_` value in a public environment variable when client code needs it; it is intentionally browser-visible.
2. **Use one stable code handle:** `defineForm({ id })`, JSX, `client.syncForm(handle, …)`, and the sync API all use an ID that is unique in the workspace. Sync returns a `formId`; use it for form links and submissions.
3. **Review before publishing:** In a claimed workspace, a first sync creates a draft and later changes stage beside the published version. A human publishes from the dashboard. A capped unclaimed preview may apply code sync live until it is claimed.
4. **Optionally restrict browser origins:** Allowed origins reduce accidental use from other sites, but callers can forge an Origin header. Review-before-publish remains the security boundary.

## Embed the published result

Once a form is published, render it with its `formId` or hosted slug. Fetching and submitting a published form does not need a publishable key. Pass a client when you use a custom API origin or build your own renderer. Add a publishable key only when syncing forms from code.

Keep the local handle and the Fillo `formId` distinct. The handle is your idempotent sync identity inside one workspace. The `formId` is the durable Fillo record returned by sync and shown by the CLI.

## Install the agent skill

Install the **Build with Fillo** skill before asking a coding agent to add a form. The default command works with Codex, Cursor, GitHub Copilot, and Gemini CLI. Claude Code needs the `--agent claude` option.

```bash
npx @usefillo/cli@latest skill install

# Claude Code uses .claude/skills
npx @usefillo/cli@latest skill install --agent claude
```

## Next steps

- [Embed quickstart](https://fillo.so/docs/embed): Render a published form by ID in React or any browser app.
- [Code-sync lifecycle](https://fillo.so/docs/authoring#lifecycle): See the detailed draft, staging, publication, and ownership model.
- [Build with agents](https://fillo.so/agents): Install the project skill and load current Markdown references as needed.
