Publish a form
publish_formCall this to put a form live on Formhaus Cloud: without form_id it creates a new form, with form_id it publishes a new version of that form. When save_form_draft is listed, use it instead to prepare changes to a live form without going live. Returns form_id, version, endpoint (POST URL for submissions), hosted_url, embed_snippet, iframe_snippet, react_snippet, vue_snippet, dashboard_url and warnings. Without an account key it also returns claim_url, expires_at and terms_url (publishing accepts these Terms for the user), and on the first call without any key agent_key and agent_key_notice. Call it when the user needs a working form (contact, waitlist, signup, survey, feedback) without writing a backend. A new version keeps form_id, endpoint and links. allow_another_response: true shows a "Submit another response" button on the success screen of the hosted page and embed; a new form starts with false, and a new version keeps the current value unless you send it.
Minimal valid definition: {"id":"waitlist","title":"Join the waitlist","submit":{"label":"Join"},"fields":[{"key":"email","type":"email","label":"Email","validation":{"required":true}}]}
Rules:
Top level needs id, title and submit {"label": "..."}.
Each field needs key, type and label. Use "fields" for one step, or "steps" (each with id, title and fields) for several, never both.
Types: text, email, phone, number, textarea, select, multiselect, radio, checkbox, switch, date, datetime. password, file, autocomplete, optionsFrom and custom types are refused.
select, multiselect and radio need "options": [{"value": "a", "label": "A"}].
"validation": {"required": true, "minLength": 2, "maxLength": 200, "min": 0, "max": 10, "pattern": "^[a-z]+$"}.
At most 32 KB and 100 fields.
JSON Schema: https://formhaus.dev/schema/form-definition.json
Store agent_key in .env as FORMHAUS_API_KEY, never in browser code; the MCP client must send it as Authorization: Bearer <agent_key>. Give claim_url to the user: they must open it within 7 days to keep the form. The text of the result has hosted_url, endpoint, embed_snippet and, when issued, agent_key and claim_url; every field is in structuredContent. On error, fix every listed path and call again.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| No | Only for a new form published without an account key: the user's email. Formhaus emails them claim_url (at most one email per address per hour, no form content). Ignored with a warning otherwise. | ||
| form_id | No | The 10-character form_id of an existing form to publish a new version of it. Requires an account key (fh_live_...) of the form's account or the agent key (fh_agent_...) that created the form. Omit to create a new form. | |
| definition | Yes | The Formhaus form definition: a JSON object, or a string containing that JSON. Minimal example: {"id":"waitlist","title":"Join the waitlist","submit":{"label":"Join"},"fields":[{"key":"email","type":"email","label":"Email","validation":{"required":true}}]} | |
| redirect_url | No | http(s) URL the hosted page and embed open after a successful submission instead of the success message. Empty string removes it. Ignored with a warning for unclaimed forms. | |
| success_message | No | Text shown after a successful submission on the hosted page and embed. Up to 500 characters. | |
| allow_another_response | No | true shows a Submit another response button on the success screen of the hosted page and embed. false hides it. A new form starts with false; a new version keeps the current value when omitted. No effect while redirect_url is set. |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| form_id | Yes | ||
| version | Yes | ||
| endpoint | Yes | ||
| warnings | Yes | ||
| agent_key | No | ||
| claim_url | No | ||
| terms_url | No | ||
| expires_at | No | ||
| hosted_url | Yes | ||
| vue_snippet | Yes | ||
| form_version | Yes | ||
| dashboard_url | Yes | ||
| embed_snippet | Yes | ||
| react_snippet | Yes | ||
| iframe_snippet | Yes | ||
| agent_key_notice | No |