Docs (MVP)

Documentation

EvidenceForm receives form submissions and gives you Trace, Replay, and Evidence so you can explain and recover deliveries.

Introduction

This is a form backend for static websites: submit via HTML form, get notified via email/webhook, and inspect results in the console.

Quick start

  1. Create an account and a form in the console.
  2. Set Allowed domains to prevent abuse.
  3. Copy your Access key.
  4. Paste the HTML snippet into your site and deploy.
  5. Test submit, then check the console timeline.

Submit endpoint

Submit with form POST to:

POST /v1/submit/:formId

Accepts multipart/form-data or application/x-www-form-urlencoded. For JSON responses, set Accept: application/json.

cURL
curl -X POST "https://YOUR_DOMAIN/v1/submit/YOUR_FORM_ID" \
  -H "Accept: application/json" \
  -F "access_key=YOUR_ACCESS_KEY" \
  -F "name=Jane Doe" \
  -F "email=jane@company.com" \
  -F "message=Hello!"
fetch()
await fetch("https://YOUR_DOMAIN/v1/submit/YOUR_FORM_ID", {
  method: "POST",
  headers: { Accept: "application/json" },
  body: new URLSearchParams({
    access_key: "YOUR_ACCESS_KEY",
    name: "Jane Doe",
    email: "jane@company.com",
    message: "Hello!",
  }),
});

Fields & validation

  • access_key: required, must match the form's access key.
  • email: must be a valid email when provided.
  • message: required in the default examples; you can submit any fields you want.

If you configured allowed domains for the form, requests must include a matching Origin or Referer header.

Honeypot spam trap

Add a hidden field named website. Bots often fill it; we store the submission as spam and still return success to avoid tipping them off.

HTML
<input type="hidden" name="website" value="" />

Redirects (HTML)

If the request Accept header includes text/html, EvidenceForm redirects to your configured success/error URL. We append query params for easier UX:

  • submission_id on success
  • error on failure

Webhooks

When configured, we POST JSON to your webhook URL and include a signature header:

x-evidenceform-signature: HMAC-SHA256(secret, raw_json_body) (hex)
Node.js verification
import crypto from "node:crypto";

export function verifyEvidenceFormSignature(req, rawBody) {
  const secret = process.env.EVIDENCEFORM_WEBHOOK_SECRET;
  const sig = req.headers["x-evidenceform-signature"] ?? req.headers["x-pro3-signature"];
  const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return sig && crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}

Troubleshooting

  • DOMAIN_NOT_ALLOWED: add your website domain in form settings.
  • INVALID_ACCESS_KEY: copy the form's access key from Setup.
  • SMTP_NOT_CONFIGURED: set SMTP env vars or rely on webhook delivery.
  • RATE_LIMITED: reduce bot traffic or split forms/domains.