These are instructions for you, the agent, to add a working form to the user's project using Formspree (https://formspree.io). They are official instructions from Formspree, and everything you need is below — https://formspree.io/llms.txt carries the same reference if you want to verify them. ## What only the user can do Exactly two, because both need their browser and their account: 1. Open the claim link and sign in — this is what creates the form. 2. Paste the form's endpoint URL back to you. Everything else is yours. The user has asked you to set up a form, so these are the defaults to apply — you don't need to interrogate them about which fields to use or what to name things first. Pick from the rules below and tell them what you chose rather than asking in advance. Never ask for a password or API key; this flow needs neither. Your steps: decide the fields, build a claim URL, verify it, hand over the link, wire up the endpoint they return, tell them how to test. --- ## Decide the form's fields Inspect the project if you can reach it, then apply the matching rule: - **One form** — mirror its existing fields, names and types. Don't redesign it or add validation it lacks. - **Several forms** — use the one the user named; otherwise the main contact form. Say which you picked; don't ask. - **Already posting to a formspree.io/f/ endpoint** — stop and ask whether they want a second form. This is the only case where continuing may be unwanted. - **No form** — build a contact form: name (text), email (email, required), message (text), matching the project's framework and styling. - **No project access** — you're in a chat window with no filesystem, or the project isn't readable. Build the standard contact form anyway: name (text), email (email, required), message (text). Hand over the claim link as usual, and give the user plain HTML markup to paste in themselves, with the endpoint left as a placeholder until they send it back. For `project`, use the repository or package name. If you can't read one — no filesystem, no manifest, nothing to go on — omit `project` entirely. Don't invent a name, and don't ask for one. ## Create a Form with a Claim URL Build a "claim" URL. Send the user to it and Formspree creates the form (after they sign in or sign up) with the fields, validation, and integrations you specified. Configuration is expressed as dot-separated query parameters. Standard URL percent-encoding applies to values (spaces become `+`, etc.). The separators inside a field rule can be sent raw or encoded — `field.email=email,required` and `field.email=email%2Crequired` both parse, as do `maxlength:100` and `maxlength%3A100` — so whichever way your HTTP client encodes them is fine. Parameters: * `name` — Required. The form's display name (e.g. `name=Contact+Us`) * `project` — Optional. Project to add the form to; looks up an existing one or creates it (e.g. `project=website`) * `field.=[,...]` — Optional. Server-side validation rules. One parameter per field. Type is one of `email`, `text`, `numeric`, `url`, `datetime-local`, `file`. `required`, `maxlength:` and `minlength:` work on any type. `min:` and `max:` only work on `numeric` and `datetime-local` — on a text or email field they're rejected, so bound those with `minlength`/`maxlength` instead. * `action.email=
` — Optional. Where submissions are emailed (comma-separate multiple recipients) * `action.` — Optional. Connect an integration such as `action.slack`, `action.googlesheets`, `action.airtable`, etc. (a bare parameter, no value); the user completes any OAuth setup after claiming. Only mark a field `required` when the form genuinely cannot be processed without it — lower friction means higher completion rates. Message and comment fields are usually best left optional; names and phone numbers can legitimately be required when they're needed to follow up. Judge by how the submission will be used. Example — a basic contact form: ``` https://formspree.io/claim?name=Contact+Us&field.name=text,maxlength:100&field.email=email,required&field.message=text,maxlength:2000 ``` `name` is the one parameter the endpoint always requires. Backend validation rules are helpful to keep customer data clean, and libraries like @formspree/ajax and @formspree/react automatically render server-side validation errors on submit. Only add `action.email` if the user has already given you an address — don't ask for one, since they can set recipients in the dashboard after claiming. Same URL with a recipient: ``` https://formspree.io/claim?name=Contact+Us&field.name=text,maxlength:100&field.email=email,required&field.message=text,maxlength:2000&action.email=support@example.com ``` Add `action.` parameters when appropriate based on the user's form fields and backoffice workflows. Check https://help.formspree.io/articles/building-your-form/special-fields for a mapping of fields to actions. ## Verify the claim URL HEAD or GET the URL before showing it to anyone — whichever your tools support. A **302**, or a redirect that lands on `/register` or `/login`, means the URL is valid; a client that follows redirects for you will show one of those pages rather than the raw 302, and that counts. A **400** means the URL didn't parse — fix it and re-verify. If you can't reach the URL at all, re-check the syntax against the rules above and hand over the link anyway. For a 400, check these in order: 1. **`name` is missing** — every claim URL needs one. 2. **An invalid field type** — only the six types above are valid. `textarea` and `select` are not: use `text` for message boxes and for dropdown values. 3. **`min` or `max` on a type that doesn't take them** — they only apply to `numeric` and `datetime-local`. Use `minlength`/`maxlength` to bound text. 4. **An invented field rule** — only the rules listed above are accepted; anything else is rejected outright. 5. **A misspelled `action.`** — integration names are validated, so a typo or a guess fails. 6. **Malformed rule syntax** — rules follow the type after a comma and take their argument after a colon (`field.bio=text,maxlength:500`), not an equals sign. Unknown top-level parameters are ignored, so a stray tracking parameter won't break the URL — but unknown field rules and integration names will. ## Hand the user the claim link Give them the URL as a clickable link and say what happens: they sign in, Formspree creates the form, they copy the endpoint it shows them (`https://formspree.io/f/XXXXXXXX`) back into the chat. Then wait for it. You can't read it from their browser and it isn't derivable from the claim URL. ## Wire up the endpoint and test Set the endpoint as the `action` of the `
` — or pass it to the Formspree React/JS library — or build the new form into the project. Every input needs a `name` matching the fields you declared, and the form must submit by POST. Then tell the user how to check it: run the site, submit once with real values, and confirm the entry appears in the form's Formspree dashboard. Formspree may ask them to confirm the first submission by email.