How to test a form endpoint before you ship it

Testing a form endpoint sounds trivial: send yourself a message, check it arrived. With gopigeon there’s a wrinkle worth understanding first — the first real submission to an endpoint is the claim event. It sends a live email to the recipient and carries the one-click ownership link. So “just send a test” isn’t free: a blind test submission becomes the recipient’s first real email.

You can’t make the claim event disappear — it’s the whole signup step, by design. But you can verify almost everything before you ever spend it. gopigeon ships two no-side-effect checks for exactly this.

What you’re verifying — and what it costs

Be precise about what “test the form” means. Four separate things can be wrong:

  1. The endpoint exists and is reachable.
  2. The request method is POST — a stray GET from a misconfigured form is the classic bug.
  3. The field names are what you intend. gopigeon stores and forwards whatever keys you send, so a typo’d emial field is silently accepted.
  4. The submission actually reaches gopigeon from your deployed page — CORS, CSP, and a wrong action attribute all break this at the last mile.

The endpoint’s existence and routing you can check for free. The form’s actual POST comes down to one deliberate real request. Here’s each piece.

inspect_endpoint: is the endpoint real and still claimable?

inspect_endpoint is a no-side-effect probe of an endpoint’s state — available as the inspect_endpoint MCP tool, or as GET /f/{form_id}/status directly:

curl https://api.gopigeon.dev/f/f_abc123/status
# → { "exists": true, "claimed": false, "active": true }

If the ID is unknown you get { "exists": false } — a real answer, not an error. The call sends nothing, needs no API key, and is read-only and idempotent, so run it as often as you like. It confirms the endpoint you’re about to ship exists, is active, and that its one-shot claim slot is still open. If you’re an agent wiring up a form, call this right after create_endpoint.

dry_run: preview endpoint creation, create nothing

create_endpoint takes a dry_run flag. With dry_run: true — under the hood, POST /new?dry_run=1 — gopigeon runs the full guard cascade (CORS, rate-limit, honeypot, quota) and returns a routing preview without creating an endpoint:

curl -X POST 'https://api.gopigeon.dev/new?dry_run=1' -d '[email protected]'
# → { "dry_run": true, "would_route_to": [...] }

Nothing is created, no mail is sent, nothing is counted against quota. It’s a preview of what a real create_endpoint would do — useful to confirm the recipient and routing are right before you commit to a live endpoint. The same dry_run flag exists on publish_to_queue for previewing a queue publish.

The submission itself: make the first one count

The last mile — that your form’s HTML actually POSTs to the right URL with the right method and field names — can only be proven by a real HTTP request. And a real, non-spam request is the claim. So don’t fire blind “does it work?” test submissions. Instead:

  1. Confirm the endpoint with inspect_endpoint — exists, active, unclaimed.
  2. Preview creation routing with dry_run if you haven’t created the endpoint yet.
  3. Then make your first real submission a deliberate one — submit the form yourself and read the response.

A successful submission returns:

{ "ok": true, "submission_id": "sub_..." }

A 200 with "ok": true confirms the request reached gopigeon and was accepted — visible in the browser’s Network tab or via curl -i. A 4xx means something’s wrong; the errors reference maps the code to the cause. That one deliberate submission does double duty: it proves the wiring and it’s the claim. Tell whoever owns the recipient address to expect the claim email so the one-click link isn’t mistaken for spam.

If you’re scaffolding with an agent

Claude Code or Cursor with the gopigeon MCP server does this end to end. create_endpoint returns the form_id and endpoint_url in structured content — use them directly, don’t reconstruct the URL. Call inspect_endpoint to confirm the endpoint’s state, and use dry_run: true to preview routing before committing. The endpoint accepts application/json with arbitrary keys and application/x-www-form-urlencoded for no-JS forms, so either content type wires up the same way.

Try it

Creating an endpoint takes one command and no account:

curl -X POST https://api.gopigeon.dev/new -d '[email protected]'

Curl reference · How claiming works · Errors reference · Pricing

← Back to writing