Form submission · explainable spam scoring · multi-destination fan-out
Drop one HTML form tag. Inkwell handles the rest — spam, fan-out, replay, retention.
The integration is a plain <form action="…">. No JavaScript required. The backend scores submissions with a transparent signal breakdown, validates against a JSON Schema you control, and fans out to email + webhook + Slack + Discord + Google Sheets + HubSpot + Mailchimp — configured per form, dispatched in parallel, retried on failure.
The canonical integration
Paste this into your HTML. That's the integration. Works on static sites, in HTML emails, inside iframes, with JavaScript off, with screen readers. The 3 KB optional widget adds inline error rendering and honeypot timing without changing the canonical path.
<form action="https://api.inkwell.philiprehberger.com/v1/forms/<form-id>/submit"
method="post">
<input name="name" required>
<input name="email" type="email" required>
<textarea name="message" required></textarea>
<input type="hidden" name="_redirect" value="https://example.com/thanks">
<input type="text" name="_subject_honeypot" style="display:none">
<button type="submit">Send</button>
</form>curl -X POST https://api.inkwell.philiprehberger.com/v1/forms/<id>/submit \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{"name":"Alice","email":"a@example.com","message":"hi"}'What's in the box
Explainable spam scoring
Every submission shows the per-signal breakdown in the admin — honeypot, IP reputation, timing, content density, email validity, captcha. Buyers see why something scored what it scored, and adjust thresholds with that signal in view. No black box.
Graduated friction, not binary block
Submissions in the 30–49 score band don't get rejected outright — they're quarantined and a captcha challenge releases them. 50+ becomes spam (no destinations dispatched). Honeypot or known-bad IP hard-blocks immediately.
Per-destination fan-out you can trust
Each destination is its own Horizon job with a (submission, destination, replay_seq) idempotency key — worker crashes never double-send. Slow OAuth connectors run on a separate queue from webhook/email/Slack so backpressure doesn't compound.
Compliance hooks ready
POST /v1/data-subjects/lookup finds every submission containing an email. DELETE /v1/data-subjects/by-email queues an async erasure that cascades through submissions, files, delivery attempts, and audit-row redaction. PII-purge cron runs at the 90-day mark. Production-shaped, not production-grade.
Webhook signing, secret rotation with grace
Webhook destinations sign payloads with HMAC-SHA256 in Stripe's t=…,v1=…format. Rotating a destination's secret keeps the old signature valid for 48 hours alongside the new one — your receivers update without dropping anything in flight.
File uploads, scanned + EXIF-stripped
Magic-byte verification against your form's MIME allowlist. Images pass through EXIF strip (GPS coordinates removed). ClamAV scan runs out-of-band — submissions acknowledge fast, infected files quarantine + flip the submission to quarantined, buyer reviews from the admin.
Destinations
Configure any combination per form. Each delivery is independent — a failed Slack notification doesn't block the webhook fan-out.
- Emailnoreply sender + Reply-To; CRLF strip on every header value
- WebhookHMAC-SHA256 t=…,v1=… + 48-hour secret rotation grace
- SlackBlock Kit, length-limit-aware
- DiscordEmbed with field mapping
- Google SheetsAppend-row by OAuth token
- HubSpotUpsert contact by email
- MailchimpAudience members, datacenter-aware