curl & MCP
Raw HTTP + MCP stdio configuration for Claude Code, Cursor, and Codex. Create endpoints at https://api.gopigeon.dev/new — no auth required.
One-liner
# 1. Create an endpoint (no auth) curl -X POST https://api.gopigeon.dev/new -d '[email protected]' # → {"endpoint_url":"https://api.gopigeon.dev/f/f_abc123def456xyz0","form_id":"f_abc123def456xyz0","unclaimed":true,"claim_note":"..."} # 2. Submit to that endpoint curl -X POST https://api.gopigeon.dev/f/f_abc123def456xyz0 \ -d 'name=Jane&[email protected]&message=hello' # → {"ok":true,"submission_id":"sub_..."}
How it works
The first curl creates an endpoint and returns a JSON payload with the live endpoint_url. The second curl submits to that URL. No auth required; the recipient email passed at creation time is where the claim link lands once a real submission arrives.
Every response is a plain JSON body (no wrapper envelope). 201 on creation, 200 on submission, 303 when a redirect_url is configured. Errors return a JSON body with an error key plus the HTTP status — see the Errors page for the full list.
Dry-run mode
Dry-run is a routing preview, not a sandbox. Append ?dry_run=1 to any submission URL and the handler runs the full request path — CORS check, honeypot, rate limit, quota read — but emits zero side effects: no submission row, no claim email, no funnel event, no quota counter increment, no AMQP publish. The response is a 200 with a JSON preview showing where the submission would have gone. Sends nothing. Use it to verify wiring before publishing your form to real users.
Contrast with sandbox mode (Mailgun-style): gopigeon has no sandbox tier. There is no test-mode inbox. Dry-run runs the live request path against the live form record and returns a preview; it does not deliver anywhere.
curl -X POST "https://api.gopigeon.dev/f/${FORM_ID}?dry_run=1" \
-H "Content-Type: application/json" \
-d '{"name":"Ada","email":"[email protected]","message":"hi"}' Returns 200 with this shape:
{
"dry_run": true,
"would_route_to": [
{"kind": "email", "target_hint": "u***@example.com"}
],
"claim_status": {
"claimed": false,
"claim_email_recipient_hint": "u***@example.com"
},
"validations_passed": ["honeypot", "rate_limit", "cors"],
"would_have_counted": {
"quota_used": 12,
"quota_remaining": 488,
"period_resets_at": "2026-06-01T00:00:00.000Z"
}
} would_route_to is an array because forms can fan out to multiple destinations after claiming. target_hint is a redacted preview (e.g. u***@example.com) — never the full address. would_have_counted shows the quota state your submission would have moved to; the live quota counter is unchanged.
The same flag works on queue publish: POST /q/${QUEUE_ID}/publish?dry_run=1 returns a preview without enqueuing an envelope.
Claim-status probe
Before sending your first real submission, verify the endpoint exists and check claim state without burning the one-shot claim event:
curl "https://api.gopigeon.dev/f/${FORM_ID}/status" Returns 200 with no PII:
{"exists": true, "claimed": false, "active": true} Returns 404 if the form doesn’t exist. The same /status suffix works for queues: GET /q/${QUEUE_ID}/status. No auth required. No submission counts. No recipient email. Use this to chain create_endpoint → probe → dry-run → real submission from an agent loop.
Dry-run and probe are free for all tiers and never count toward the 50/mo form quota or the 100/mo queue quota. Hammer them in CI without worry — there's a separate 60/min/IP rate limit so a flood test doesn't exhaust your real-submission rate-limit bucket.
Claude Code install
# Anonymous mode — exposes create_endpoint only claude mcp add --transport stdio gopigeon -- npx -y @gopigeon/mcp@^0.1.0 # With API key for get_submissions + list_endpoints claude mcp add --transport stdio --env GOPIGEON_API_KEY=YOUR_KEY gopigeon -- npx -y @gopigeon/mcp@^0.1.0
Cursor / generic JSON config
{ "mcpServers": { "gopigeon": { "type": "stdio", "command": "npx", "args": ["-y", "@gopigeon/mcp@^0.1.0"], "env": { "GOPIGEON_API_KEY": "${GOPIGEON_API_KEY}" } } } }
Owned mode
Set GOPIGEON_API_KEY (generate one in the dashboard) and create_endpoint routes to OWNED mode automatically — no claim email, no trial TTL, no 30-day expiry. The owned path calls POST /api/forms with Bearer auth and skips the anonymous claim handshake entirely.
For multi-destination endpoints, supply a destinations array at creation time:
{
"name": "My endpoint",
"destinations": [
{"type": "managed-email", "to": "[email protected]"},
{"type": "webhook", "url": "https://example.com/hook"}
]
} Once created, manage the endpoint with the sibling MCP tools: update_endpoint (name / redirect URL / allowed origins / active flag), add_destination, list_destinations, remove_destination. See /docs/destinations for destination type options.
The email you passed as recipient above gets a one-click claim link on the first real submission — that is how you become the authenticated owner. See the claim flow for the full sequence.
Useful flags
redirect_url— after claiming, set this in the dashboard to send submitters to a thank-you page (HTTP 303). Without it, the response body is raw JSON._gotcha— reserved honeypot field name. Drop<input name="_gotcha" tabindex="-1" style="position:absolute;left:-9999px" aria-hidden="true">in your form. Any submission where_gotchais non-empty is silently dropped as spam.allowed_origins— defaults to*. After claiming, lock down to a comma-separated list of HTTPS origins on the endpoint’s dashboard page.