> ## Documentation Index
> Fetch the complete documentation index at: https://formpaste.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrating from Formspree

> Swap your existing form's endpoint and auth field - what changes, what maps over, and what doesn't exist yet.

If you already have a working Formspree-backed form, moving it to Formpaste is mostly
a two-line change: a different `action` URL, and a hidden field instead of the endpoint
ID being baked into the URL. This guide covers the swap itself and the handful of
behavioral differences worth knowing before you flip the switch, so nothing breaks
silently.

## The core swap

A typical Formspree form posts straight to an endpoint with your form ID embedded in
the URL:

```html theme={null}
<form action="https://formspree.io/f/xxxxxxxx" method="POST">
  <input type="email" name="email" required>
  <textarea name="message" required></textarea>
  <button type="submit">Send</button>
</form>
```

The Formpaste equivalent posts to a single, shared endpoint - `/submit` - and instead
identifies your form through a hidden `access_key` field in the body, not through the
URL:

```html theme={null}
<form action="https://api.formpaste.com/submit" method="POST">
  <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY">
  <input type="email" name="email" required>
  <textarea name="message" required></textarea>
  <button type="submit">Send</button>
</form>
```

Two changes, nothing else: the `action` URL, and one new hidden `access_key` input.
Every other field - your `email`, `message`, or whatever custom fields your form
already has - keeps its name and works unchanged, since neither service reserves those
names.

Get your `access_key` (`fp_…`) by creating a form in the
[dashboard](https://app.formpaste.com) (or asking an agent to do it via the MCP
[`create_form`](/docs/agents/create-form) tool) - see [Your first form](/docs/first-form) if
you're starting from scratch.

## If you're using Formspree's AJAX/fetch integration

The pattern is the same shape, just pointed at a different URL and with `access_key` in
the body instead of the endpoint path:

```js theme={null}
const form = new FormData(e.currentTarget);
// form already has your normal fields - add the access key:
form.append("access_key", "YOUR_ACCESS_KEY");

const res = await fetch("https://api.formpaste.com/submit", {
  method: "POST",
  body: new URLSearchParams(form),
});
```

Formpaste's success response is a `200` with
`{"success": true, "message": "Submission received.", "id": "sub_..."}` - check
`res.ok` or `success` the same way you'd have checked Formspree's response.

## Mapping the rest of your setup

| Formspree concept                      | Formpaste equivalent                                                                                         |
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| Endpoint ID in the URL (`/f/xxxxxxxx`) | `access_key` field in the request body, `/submit` is shared                                                  |
| Email notification                     | [Email notifications](/docs/features/notifications) - verify the destination once (OTP), on by default after that |
| Redirect after submit (`_next` field)  | `redirect` field - see [Redirects](/docs/features/redirects); must be on the form's allowed-domains list          |
| Honeypot / spam field                  | `botcheck` - see below, naming is different                                                                  |
| reCAPTCHA / hCaptcha integration       | Not applicable - Formpaste has no CAPTCHA of any kind; see [Preventing spam](/docs/guides/preventing-spam)        |
| Allowed domains                        | [Domain allowlist](/docs/features/custom-domains) - configured per form in the dashboard                          |
| Submission dashboard                   | Formpaste [dashboard](https://app.formpaste.com) inbox + spam tabs                                           |
| Zapier/integrations                    | Only [webhooks](/docs/features/webhooks) (Pro) are built; see the differences section below                       |

## Differences worth knowing before you switch

**No spam puzzles.** If your Formspree form had reCAPTCHA or hCaptcha wired in,
just remove it - don't look for an equivalent to configure. Formpaste relies entirely
on server-side heuristics (honeypot, timing, link density, rate, disposable-email) that
never show your visitor a puzzle. If you had a honeypot field for Formspree, rename it
to `botcheck` - that's the specific name Formpaste checks - and hide it with CSS
(`display:none`), not `type="hidden"`, so unsophisticated bots that skip hidden inputs
still fall for it. See [Preventing spam](/docs/guides/preventing-spam).

**Suspicious submissions are quarantined, not silently dropped or blocked.** A
submission that scores as spam still lands somewhere you can see it - the dashboard's
Spam tab - rather than vanishing. On Free that view is read-only; re-delivering a
false positive ("rescue") is a [Pro](/docs/features/quarantine-rescue) action. If your
Formspree spam filter silently discarded submissions, budget time to check the
quarantine tab occasionally after migrating, in case anything legitimate needs a nudge.

**No REST API for forms or submissions.** Formpaste doesn't have a general
create-form/list-submissions REST API. Forms are created in the dashboard or via the
MCP `create_form` tool; submissions are read via the dashboard, CSV export, or the MCP
`list_submissions` tool - see [Retrieving submissions](/docs/reference/submissions-api) if
you were scripting anything against Formspree's API surface.

**An MCP server, if you're wiring this up with an agent.** If you're migrating a form
with the help of Claude Code, Cursor, or another MCP-speaking agent, it can create the
form and hand you back a wired snippet directly - see [MCP server](/docs/agents/mcp-server)
and the [cookbook prompts](/docs/agents/cookbook-prompts). This isn't a Formspree
equivalent; it's new surface Formpaste has that Formspree doesn't.

**Plans are simpler.** Formpaste has exactly two plans - Free and Pro (four
submission-quota tiers within Pro) - rather than [Formspree's multi-tier structure](https://formpaste.com/alternatives/formspree/). See
[Pro plan](/docs/features/pro-plan) if you're evaluating whether your current usage fits
Free's 250 submissions/month.

## After you switch

1. Update the `action` URL and add `access_key` on every form you're migrating.
2. Verify each form's destination email (one-time OTP per address) - see
   [Your first form](/docs/first-form).
3. Rename any honeypot field to `botcheck` and confirm it's hidden with CSS.
4. Remove any CAPTCHA widget/script - it isn't needed and Formpaste won't read it.
5. Set the [domain allowlist](/docs/features/custom-domains) once you've confirmed
   submissions are arriving, so the form isn't left open to any origin indefinitely.
6. Submit a real test and confirm it lands in the dashboard inbox and your email.

<CardGroup cols={2}>
  <Card title="Your first form" icon="inbox" href="/docs/first-form">
    Full walkthrough for creating a form and verifying its destination.
  </Card>

  <Card title="Framework snippets" icon="brackets-curly" href="/docs/framework-snippets">
    Wired examples for HTML, React, Next.js, Astro, Vue, and Svelte.
  </Card>

  <Card title="Preventing spam" icon="shield" href="/docs/guides/preventing-spam">
    How filtering works.
  </Card>

  <Card title="Retrieving submissions" icon="database" href="/docs/reference/submissions-api">
    Dashboard, CSV export, and the MCP tool - no REST API.
  </Card>
</CardGroup>
