Home
Reliable form ingestion and webhook delivery for developers.
Every project with a contact form, a waitlist, or a feedback box needs the same small backend: something that accepts an HTML form POST, validates it, stores it, and forwards it somewhere useful. Writing that once is easy. Running it reliably, with retries, delivery logs and an audit trail, is not.
Hymical Forms is that backend, self-hostable and open source. Point an HTML
form's action at it and every submission is validated, stored, and delivered to
your webhook with an HMAC signature and a bounded retry schedule.
What you get¶
-
Public form ingestion
A URL you can put straight in a
<form action="...">. No credential, no JavaScript, no CORS dance. Rate limited per source address and per endpoint. -
Delivery that survives a crash
A submission and the obligation to deliver it are written in one database transaction. Once the API answers
202, the delivery cannot be lost. -
Signed, retried webhooks
HMAC-SHA256 over the raw body, a separate worker process, exponential backoff, and a full attempt history you can read back.
-
Safe retries
Send an
Idempotency-Keyand a repeated request returns the original submission instead of storing the form twice. -
Submissions you can read back
Browse and filter what your forms collected, read one submission in full, and export a range as JSON or CSV. Authenticated, always.
-
Retention you control
Nothing is deleted until you run the cleanup command, and it never removes a submission a delivery could still need.
Requirements¶
- Python 3.11 or newer
- PostgreSQL, which is the intended production database
SQLite is supported for local experimentation and backs the test suite. It is not a supported production target.
Install¶
export FORMS_DATABASE_URL=postgresql+psycopg://forms:forms@localhost:5432/forms
alembic upgrade head
Full steps are in Installation.
A first submission¶
Create an endpoint, then point a form at it:
<form action="http://127.0.0.1:8000/f/contact-form" method="POST">
<input type="email" name="email" required />
<textarea name="message"></textarea>
<button type="submit">Send</button>
</form>
{
"submission_id": "sub_48984534f33749c49a88de2d59400dce",
"endpoint_id": "contact-form",
"received_at": "2026-08-24T14:34:27.651841Z",
"field_count": 2,
"idempotent_replay": false,
"delivery": { "queued": true }
}
The Quick Start takes you from a clone to that response in about five minutes.
Where to go next¶
-
Getting Started
Install, configure a database, migrate it, create a management key, and accept your first submission.
-
Guides
How ingestion, idempotency, webhooks, rate limiting, endpoint management, delivery replay and submission export actually behave.
-
API Reference
Every route, its parameters, its responses, and the complete error table.
-
Operations
Running the worker, applying migrations, sweeping expired submissions, sitting behind a reverse proxy, and every configuration variable.
-
Architecture
The outbox, at-least-once delivery, the concurrency model, and the security boundaries.
-
Data handling
Where a submitted value goes, where it never goes, and what deleting one does and does not remove.
-
Limitations
An honest list of what this build does not do yet. Worth reading before you deploy it.
Project status¶
Early development. The service registers endpoints, stores submissions with the durable obligation to deliver them, and runs a worker that performs the signed delivery and retries it. Endpoint management, delivery inspection, manual replay, public ingestion rate limiting, submission retrieval and export, and operator-run retention cleanup are all implemented and covered by tests, including a PostgreSQL suite that exercises real concurrency.
There is no spam protection, no CAPTCHA and no content classification. Rate limiting bounds volume, not junk. Retention is never automatic: nothing is deleted until an operator runs the cleanup command. See Limitations for the full picture.