Menu

Errors

HTTP status codes and the conditions that produce them. Consult this before retrying a failed request.

StatusMeaningTypical cause
400validation failedmissing recipient, invalid email, placeholder email (example.com, your-email, etc.)
410endpoint expired30-day TTL elapsed without submissions
429rate limited or cap reached>10 creations/hour/IP, or 50-submission lifetime cap reached

Example 400

curl -i -X POST https://api.gopigeon.dev/new -d 'recipient=not-an-email'
# HTTP/1.1 400 Bad Request
# {"error":"validation failed","field":"recipient"}

Dry-run response (not an error)

Submissions sent with ?dry_run=1 always return HTTP 200 with a JSON body whose top-level field is "dry_run": true — there is no error key. If your client treats any 200 + non-empty JSON body as success, dry-run will look like a normal successful submission but the body shape is different.

Distinguishing key: the dry-run body’s top-level fields are dry_run, would_route_to, claim_status, validations_passed, would_have_counted. The real-submission body has ok, submission_id. The 400/410/429 error bodies have error, plus optionally field, code, _help. The three response shapes are disjoint — no single field name appears in more than one.

Minimal dry-run body excerpt:

{
  "dry_run": true,
  "would_route_to": [{"kind": "email", "target_hint": "u***@example.com"}],
  "claim_status": {"claimed": false},
  "would_have_counted": {"quota_used": 12, "quota_remaining": 488}
}

Dry-run is a routing preview only — sends nothing. See /docs/curl for the full response contract and curl examples on both form and queue endpoints. The dry-run flag never produces a 4xx on its own; if the underlying request fails CORS, honeypot, or rate-limit, you’ll get the same 4xx you’d see in a real submission (because dry-run with ?dry_run=1 runs the full guard cascade). So a 403 with ?dry_run=1 means the same thing as a 403 without it — it just doesn’t consume any quota either way.

Retry guidance

  • 400: fix the payload and re-send; the response body names the offending field.
  • 410: create a new endpoint — expired endpoints cannot be resurrected.
  • 429: back off and retry later. The Retry-After header, when present, is authoritative.

Not what you're looking for? See the full surface at /llms.txt.