docs
stormdoor.dev
REFERENCE

Errors & fail-open

One error shape, stable codes, and what fail-open actually means.

One shape for every error, with a stable machine-readable code and no stack traces:

{ "ok": false, "error": { "code": "quota_exceeded", "message": "...", "fail_open": true } }

invalid_request errors return field paths only — never the value you submitted, even to help you debug. Echoing a rejected payload back would be exactly the retention leak this API's no-payload-retention rule exists to prevent.

Error codes#

CodeStatusNotes
invalid_request400Schema validation failed.
unauthorized401Missing or invalid key.
quota_exceeded402Fail open.
plan_required403Key is valid, but the gate isn't on your plan.
not_found404
method_not_allowed405Wrong HTTP method. Not fail-open.
payload_too_large413Rejected while streaming, before the body is buffered.
unsupported_media_type415
rate_limited429Carries Retry-After.
internal_error500Fail open.
gate_unavailable503Fail open.
origin_not_allowed403The request carried a browser Origin header. Not fail-open — see authentication.

What fail-open means#

This API sits in the request path of someone's signup or contact form. fail_open: true appears on exactly three codes — quota_exceeded, internal_error, gate_unavailable — and it's a flag your integration branches on, not something the API decides for you.

Two parties, two behaviours — don't conflate them. The API always returns the error envelope above and no verdict at all when something goes wrong on our side. There's no success envelope with a null verdict, and no third response shape. Failing open is what your own SDK or integration code does with that error — typically treating it as clean so the form isn't blocked by an outage — not something the API itself asserts about the input it never actually screened. If you show a caller-facing status for this, say "no verdict," not "clean": nothing was checked, so claiming a clean result would be a screening outcome StormDoor never produced.