caputchin
All docs
View raw .md

Hosted verification

A paid feature for customers without a backend. The customer points their form at a Caputchin URL instead of their own server; the platform verifies the wrapped token and forwards the submission to a webhook, an email address, or both.

The decision and rationale (paid-only, no submission storage, webhook + email scope) live in ADR-0007. This page covers what the feature is, who it's for, how it fits the system, and what it deliberately is not.

Who it's for

  • Static sites (Webflow, Framer, plain HTML on a CDN)
  • No-code builders (Wix, Squarespace, Carrd)
  • Solo developers and small teams who don't want to run a backend just to handle a contact form
  • Anyone using Caputchin who finds setting up server-side verification a hassle

How it changes the integration

The customer-visible HTML barely changes. Same <caputchin-widget> element, same form fields. The only difference is the form's action attribute — it points at a Caputchin forwarder URL instead of the customer's own backend. See the setup guide for the walkthrough.

Where it sits in the system

The forwarder is a route inside the web app on the forward.caputchin.com subdomain — same Cloudflare deploy, same database, same code base as the dashboard and Platform API. It is a distinct product surface (own customer contract, own billing gate, own trust-model row) but not a separate operational service. See deployment and ADR-0010.

The route owns: receiving the form POST, calling /siteverify internally with the platform's own secret, dispatching to the configured destinations (webhook via signed fetch, email via Resend). It does not own: storing the submission, retrying indefinitely, or transforming the payload beyond what each destination requires.

End-to-end flow

sequenceDiagram
  autonumber
  participant U as User
  participant B as Browser (caputchin widget)
  participant F as Caputchin forwarder
  participant V as /siteverify
  participant D as Customer destination<br/>(webhook or email)

  U->>B: Fill form, submit
  B->>F: POST form payload (incl. caputchin-token)
  F->>V: Verify token (platform's own secret)
  V-->>F: Verification result
  alt Token valid
    F->>D: Deliver submission (signed POST or email)
    D-->>F: Acknowledge
    F-->>B: 200 OK (redirect / thank-you)
  else Token invalid or missing
    F-->>B: 400 (rejected)
  end

The forwarder holds the submission in memory only for the duration of the dispatch. There is no persistence layer between steps 2 and 4 — see ADR-0007.

Destinations

Customers configure one or both per site key. See the dashboard for where this lives.

Destination What customer receives Delivery shape
Webhook Signed POST containing the form payload plus verification metadata Customer's handler verifies the signature using a webhook signing key issued by the dashboard, then processes the submission
Email Plain email with the form fields and a footer noting Caputchin verified the submission Sent via Resend; customer sees a clean inbox-friendly message

Both can be enabled simultaneously on a single site key — useful for "log to webhook for processing, email me a copy" patterns.

Rate limiting

Caputchin applies rate limits per site key to protect both our forwarder infrastructure and the customer's downstream destinations from overload. The limits are not customer-configurable — sensible defaults per pricing tier, set by Caputchin and adjusted as we observe abuse patterns.

Privacy stance

The forwarder reinforces rather than weakens the structural privacy posture:

  • Submission contents are not stored. They exist in process memory for the duration of the forward, then go.
  • No analytics on submitters. The forwarder does not collect submitter IPs, user agents, geolocation, or any per-user data — same posture as the rest of the platform.
  • Forwarder logs carry no payload data. Aggregate counters and error codes only, mirroring the aggregate-stats model.

See the privacy doc for the full inventory.

What is intentionally absent

  • No submission storage or "submission inbox" UI. Build a record on the webhook end if you want one.
  • No first-party Discord / Slack / Telegram / SMS adapters. Webhook + email only. Customers wanting more shapes use Zapier, Make, or their own webhook handler.
  • No custom forwarder domains at MVP. Forwarder URLs live under our domain; custom domains stay deferred entirely as a future enterprise tier.
  • No free tier. Paid only — see ADR-0007 for why.
  • No customer-configurable rate limits. Defaults per pricing tier; we own the knob.
  • No payload transformation. What the form posts is what the webhook receives (plus verification metadata). No field mapping, templating, or schema enforcement.

Why it works as a paid feature

Hosted verification removes the largest remaining adoption objection ("I don't have a backend"). On the free tier the customer hits that wall and has a clear upgrade path: pay for hosted verification and ship in minutes. The feature has real marginal cost (forwarder runtime, email delivery via Resend) that maps cleanly onto subscription pricing, and the paid gate filters spammers out of the customer base.

Brand fit

Same posture as the rest of the platform: privacy-first (no submission storage), honest about what's verified (uses the same /siteverify everyone else uses, just with the platform's own secret on the customer's behalf), and opinionated about scope (webhook + email, not everything). See principles.