# Formspree Create Form Skill

Use this skill when a user wants you to set up a Formspree form for them without making API requests yourself.

## What Formspree Does

Formspree hosts form endpoints for static sites, React apps, and server-rendered apps. You define the fields and actions you want, then the user claims the form in their Formspree account and gets a live endpoint they can plug into their site.

This skill is built around a URL-based claim flow:

1. You construct a claim URL with flat query parameters describing the form.
2. You send the user a link to `https://formspree.io/claim?name=...&field.email=...&action.email=...`.
3. The user clicks it, logs in or registers, and Formspree creates the form.
4. The user lands on the integration page and can paste the form endpoint back into chat.

## What You Should Send The User

When you finish building a claim URL:

1. Tell the user what the form will do (fields, actions).
2. Give them the claim URL using a **markdown link** to keep the message clean.
3. Tell them to click it and complete login or registration.
4. If the config includes actions that require a paid plan (autoresponse, webhook) or OAuth (Slack, Trello, etc.), mention that Formspree will show a setup page where they can connect or remove those actions.
5. Tell them that after claiming the form, they should paste the form endpoint back into the chat so you can wire it into their code.

IMPORTANT: Always use a markdown link `[link text](url)` rather than displaying the raw URL, since claim URLs can be long.

Use wording like:

> I have configured a Formspree form with the following: (description of form). [Click here to claim your form](<claim URL>). After Formspree finishes setup, paste the form endpoint back here and I will integrate it into your site code.

## Claim URL Format

The claim URL uses flat query parameters — no base64 or JSON encoding step needed. Standard URL percent-encoding still applies to parameter values: spaces become `+` or `%20`, and characters like `&`, `=`, `#` must be percent-encoded (`%26`, `%3D`, `%23`). This matters most for free-text values like `action.autoresponse.message` and `action.autoresponse.subject`, which are likely to contain punctuation.

```text
https://formspree.io/claim?name=Contact+Us&project=website&field.email=email,required&field.message=text,required,maxlength:2000&action.email=support@example.com
```

### Form Metadata

| Param     | Description                        |
| --------- | ---------------------------------- |
| `name`    | Form display name (required)       |
| `project` | Project name (looks up or creates) |

### Fields: `field.<name>=<type>[,<rule>...]`

Each field is a single param. The key is `field.<field_name>`, the value is the field type followed by comma-separated rules.

```
field.email=email,required
field.message=text,required,maxlength:2000
field.age=numeric,min:18,max:120
field.resume=file,accept:application/pdf
field.start_date=datetime-local,min:2025-01-01T00:00
```

**Field types**: `email`, `text`, `numeric`, `url`, `datetime-local`, `file`

Field names should start with an alphanumeric character.

### Field Rules

| Rule           | Syntax                      | Notes                                           |
| -------------- | --------------------------- | ----------------------------------------------- |
| required       | `required`                  | Boolean flag — presence means true              |
| maxlength      | `maxlength:<n>`             | Max string length                               |
| minlength      | `minlength:<n>`             | Min string length                               |
| max            | `max:<n>`                   | Max numeric/datetime value                      |
| min            | `min:<n>`                   | Min numeric/datetime value                      |
| accept         | `accept:<mime>[;<mime>...]` | MIME types for file fields, semicolon-separated |
| blockFreemails | `blockFreemails`            | Boolean flag — reject free email domains        |
| prettyName     | `prettyName:<label>`        | Human-friendly field label                      |

Rules with values use `key:value` syntax. Boolean rules are bare keywords (presence = true).

MIME types in `accept` use semicolons instead of commas since comma is the rule delimiter: `accept:application/pdf;image/png`.

Notes:

- For `datetime-local`, `min` and `max` should be datetime strings (e.g., `min:2025-01-01T00:00`).
- For `numeric`, `min` and `max` should be numbers.
- `prettyName` labels must not contain commas or colons — these characters conflict with rule delimiters and will cause incorrect parsing.
- Keep field names simple and stable because they become submission keys.

### Actions: `action.<name>[=<value>]` / `action.<name>.<key>=<value>`

All actions use the `action.` prefix. The format depends on what config the action needs:

**No config (OAuth apps)** — bare param, no value needed:

```
action.slack
action.googlesheets
action.trello
```

The user completes OAuth setup after claiming. The server accepts bare params (no `=`), empty values (`action.slack=`), or `action.slack=true` — presence is all that matters.

**Single value** — `action.<name>=<value>`:

```
action.email=support@example.com
action.webhook=https://example.com/form-hook
action.discord=https://discord.com/api/webhooks/...
```

For multiple email recipients, comma-separate them:

```
action.email=alice@example.com,bob@example.com
```

**Multiple config fields** — `action.<name>.<key>=<value>`:

```
action.autoresponse.subject=Thanks+for+reaching+out
action.autoresponse.message=We+received+your+message
action.autoresponse.fromName=Support+Team
```

### Captcha

Optional spam protection:

```
captcha=recaptcha
```

Only `recaptcha` type is supported. The reCAPTCHA secret must be configured in the dashboard after the form is created.

## Action Reference

### Credential-Free Actions

These can be fully configured in the claim URL. Note that `autoresponse` and `webhook` require a paid plan — on free accounts they will be created in a disabled state and the user will see a "finish setup" page where they can upgrade or remove them.

#### Email Notification

Docs: https://help.formspree.io/hc/en-us/articles/44775790301331-Plugins

```
action.email=support@example.com
```

For multiple recipients, comma-separate them: `action.email=alice@example.com,bob@example.com`

#### Webhook

Docs: https://help.formspree.io/hc/en-us/articles/360015234873-Webhooks

```
action.webhook=https://example.com/form-hook
```

#### Autoresponse

Docs: https://help.formspree.io/hc/en-us/articles/360025007233-Sending-a-confirmation-or-response-email

```
action.autoresponse.subject=Thanks+for+reaching+out
action.autoresponse.message=We+received+your+message
action.autoresponse.fromName=Support+Team
```

Optional key: `action.autoresponse.template`

#### Discord

Docs: https://help.formspree.io/hc/en-us/articles/1500002137941-Send-Discord-notifications

```
action.discord=https://discord.com/api/webhooks/...
```

### Actions Requiring Authorization

These actions are created in a disabled state when claimed. The user authorizes them via OAuth or configures credentials on the finish-setup page after claiming. Use bare params — do not embed API keys or tokens in the claim URL.

#### Airtable

Docs: https://help.formspree.io/hc/en-us/articles/360043997954-Use-Airtable-to-create-powerful-spreadsheets

```
action.airtable
```

#### ActiveCampaign

Docs: https://help.formspree.io/hc/en-us/articles/34570233136019-Use-ActiveCampaign-to-create-contacts

```
action.activecampaign
```

#### Asana

Docs: https://help.formspree.io/hc/en-us/articles/31937573450131-Use-Asana-to-create-tasks

```
action.asana
```

#### ConvertKit

Docs: https://help.formspree.io/hc/en-us/articles/45708297192851-Add-Subscribers-to-ConvertKit-Lists

```
action.convertkit
```

#### Constant Contact

Docs: https://help.formspree.io/hc/en-us/articles/32082743140115-Use-Constant-Contact-to-create-contacts

```
action.constantcontact
```

#### Freshdesk

Docs: https://help.formspree.io/hc/en-us/articles/1500003176541-Use-Freshdesk-to-create-support-tickets

```
action.freshdesk
```

#### GitHub

Docs: https://help.formspree.io/hc/en-us/articles/16176138448787-Use-Github-to-add-issues-to-a-repository

```
action.github
```

#### Gladly

Docs: https://help.formspree.io/hc/en-us/articles/1500005251262-Use-Gladly-to-create-tasks

```
action.gladly
```

#### Google Sheets

Docs: https://help.formspree.io/hc/en-us/articles/360036563573-Use-Google-Sheets-to-send-your-submissions-to-a-spreadsheet

```
action.googlesheets
```

#### Gorgias

Docs: https://help.formspree.io/hc/en-us/articles/1500006150742-Use-Gorgias-to-create-support-tickets

```
action.gorgias
```

#### HubSpot

Docs: https://help.formspree.io/hc/en-us/articles/360043698174-Use-HubSpot-to-create-leads-and-contacts

```
action.hubspot
```

#### Klaviyo

Docs: https://help.formspree.io/hc/en-us/articles/8614020674579-Adding-subscribers-to-Klaviyo-list

```
action.klaviyo
```

#### Mailchimp

Docs: https://help.formspree.io/hc/en-us/articles/360036061994-Use-Mailchimp-to-collect-email-addresses

```
action.mailchimp
```

#### MailerLite

Docs: https://help.formspree.io/hc/en-us/articles/1500002136742-Use-MailerLite-to-create-subscribers

```
action.mailerlite
```

#### Notion

Docs: https://help.formspree.io/hc/en-us/articles/17381343338259-Use-Notion-to-add-submissions-to-a-database

```
action.notion
```

#### Pipedrive

Docs: https://help.formspree.io/hc/en-us/articles/1500010739681-Use-Pipedrive-to-create-leads-and-contacts

```
action.pipedrive
```

#### Salesforce

Docs: https://help.formspree.io/hc/en-us/articles/33314677333011-Use-Salesforce-to-create-Leads

```
action.salesforce
```

#### Slack

Docs: https://help.formspree.io/hc/en-us/articles/360045648933-Send-Slack-notifications

```
action.slack
```

#### Stripe

Docs: https://help.formspree.io/hc/en-us/articles/360053306013-Use-Stripe-to-accept-payments-with-SCA

```
action.stripe
```

#### Telegram

Docs: https://help.formspree.io/hc/en-us/articles/6989843323923-Use-Telegram-to-receive-messages

```
action.telegram
```

#### Trello

Docs: https://help.formspree.io/hc/en-us/articles/360034260534-Use-Trello-to-create-cards

```
action.trello
```

#### Zapier

Docs: https://help.formspree.io/hc/en-us/articles/360036624813-Connecting-a-form-to-Zapier

```
action.zapier
```

#### Zendesk

Docs: https://help.formspree.io/hc/en-us/articles/360034793613-Use-Zendesk-to-create-support-tickets

```
action.zendesk
```

## URL Size Guidelines

The server rejects claim configs larger than `4096` bytes (total query string).

Practical guidance:

- Prefer short field names and concise labels
- Avoid embedding long message bodies unless needed
- Avoid large numbers of actions in one claim URL

## Worked Examples

### Contact Form

```
/claim?name=Contact+Us
  &project=website
  &field.name=text,required,maxlength:100
  &field.email=email,required
  &field.message=text,required,maxlength:2000
  &action.email=support@example.com
  &action.autoresponse.subject=Thanks+for+contacting+us
  &action.autoresponse.message=We+received+your+message+and+will+get+back+to+you+soon
  &action.autoresponse.fromName=Support+Team
```

### Newsletter Signup

```
/claim?name=Newsletter+Signup
  &project=marketing
  &field.email=email,required
  &action.email=marketing@example.com
  &action.autoresponse.subject=You+are+subscribed
  &action.autoresponse.message=Thanks+for+joining+our+newsletter
  &action.autoresponse.fromName=Marketing+Team
```

### Support Ticket with Slack and Trello

```
/claim?name=Support+Request
  &project=support
  &field.email=email,required
  &field.order_id=text,maxlength:50
  &field.priority=text
  &field.details=text,required,maxlength:4000
  &action.email=support@example.com
  &action.slack
  &action.trello
```

### Simple Form with Just Email Notification

```
/claim?name=Feedback&field.email=email,required&field.comment=text,required&action.email=team@example.com
```

## Agent Checklist

Before sending a claim URL:

1. Include `name` — it is the only required param.
2. Make sure field names start with an alphanumeric character.
3. Make sure action names match an accepted action exactly (e.g., `action.email`, `action.slack`, `action.googlesheets`).
4. Percent-encode parameter values. Free-text values like `action.autoresponse.message` and `action.autoresponse.subject` are likely to contain characters that must be encoded: `&` → `%26`, `=` → `%3D`, `#` → `%23`, `+` → `%2B` (literal plus sign). Spaces should be encoded as `+` or `%20`.
5. Keep the total URL under 4 KB (the server rejects larger query strings).
6. Send the user the claim URL using a markdown link: `[Click here to claim your form](url)`.
7. Ask the user to paste the resulting form endpoint back into the conversation.

## Close The Loop

After the user claims the form, ask for the live endpoint. Example:

> Formspree should now show you the form endpoint on the integration page. Paste that endpoint here and I will wire it into your HTML, React component, or backend code.
