Features

Everything the app does today.

Below is a faithful summary of behavior in the codebase — not a roadmap slide.

  • Instant JSON endpoints

    Each form exposes POST /api/s/{slug} with application/json only. No API key is required for public submission (ownership is enforced on reads and exports).

  • Spam scoring

    Submissions are scored from field names and values: honeypot-style field names, URL density in text, suspicious keywords, and repeated-character patterns. When the score reaches the configured threshold, the request is rejected as spam (HTTP 202) and counted on the form without creating a submission row.

  • Form lifecycle

    Forms have a unique slug, optional description, and an ACTIVE or PAUSED status. Paused forms return FORM_PAUSED and do not accept new payloads.

  • Dashboard analytics

    Per-form dashboard shows volume stats, a time-range chart for accepted submissions, and the exact endpoint URL using your configured APP_URL (or localhost in development).

  • Pause and resume

    Toggle acceptance from the form dashboard without deleting the form or losing history.

  • Export submissions

    Signed-in owners can download filtered submissions as JSON or CSV via GET /api/forms/{id}/submissions/export with optional status and date range query parameters.

  • Email alerts (planned)

    The schema includes submissionEmailAlerts on forms for future owner notifications; delivery is not wired in the application yet.

Payload rules (public API)

Bodies must be a single JSON object whose values are only strings, numbers, booleans, or null — no nested objects or arrays. Maximum encoded size is 5KB. Wrong content types, malformed JSON, or invalid shapes return structured error payloads with HTTP 4xx codes.