# FormBack — Full LLM Documentation > Form backend service for static sites. Receive form submissions via email, webhooks, Slack, and Discord — no server code needed. Website: https://formback.email API Base: https://api.formback.email Documentation: https://formback.email/docs --- ## Overview FormBack is a form backend-as-a-service. You create a form endpoint, point your HTML form's `action` attribute to it, and FormBack handles receiving submissions, sending notifications, and storing data. No backend code required. --- ## Quick Start 1. **Sign up** at https://formback.email/login (free, no credit card required) 2. **Create a form** in your dashboard — click "New Form" and copy the endpoint URL 3. **Add to your HTML:** ```html
``` --- ## Features ### Email Notifications Get an email for every new submission. Configure recipient addresses in form settings. Enabled by default. ### Webhooks Forward submissions to any URL — Slack, Zapier, your own API. Configure webhook URLs in form settings. Webhook payload: ```json { "event": "submission.created", "form": { "id": "abc123", "name": "Contact Form" }, "submission": { "id": "sub_001", "data": { "name": "John", "email": "john@example.com", "message": "Hello!" }, "createdAt": "2025-01-15T12:30:00Z" } } ``` ### Slack Integration Native Slack webhook support. Add a Slack Incoming Webhook URL to your form settings and receive formatted notifications in your Slack channel. ### Discord Integration Native Discord webhook support. Add a Discord Webhook URL to your form settings and receive formatted notifications in your Discord channel. ### Spam Protection Built-in honeypot field (`_gotcha`). Add a hidden field to your form — bots fill it, humans don't. Submissions with a `_gotcha` value are silently rejected (returns success to not reveal detection). ```html ``` ### Custom Redirects Redirect users to a custom thank-you page after submission. Two ways: 1. Set `redirect_url` in form settings (applies to all submissions) 2. Add a `_next` hidden field in your form (per-form override) ```html ``` ### File Uploads Accept file attachments using `multipart/form-data`. Files are stored securely and accessible via API. **Limits:** - Maximum 5 files per submission - Maximum 10MB per file - Maximum 25MB total per submission ```html
``` ### Supported Field Types FormBack accepts any standard HTML form fields: text, email, textarea, file, select, checkbox, radio, number, tel, url, date, hidden. --- ## API Reference Base URL: `https://api.formback.email` ### Authentication All API requests (except form submission) require an API key in the `Authorization` header: ``` Authorization: Bearer YOUR_API_KEY ``` Get your API key from the Account page at https://formback.email/account. API keys can be scoped to specific forms for security. ### Form Submission (Public) **`POST /f/:formId`** Submit a form. This is the public endpoint — no authentication required (optionally supports `X-API-Key` header for programmatic submissions). **Content Types:** - `application/x-www-form-urlencoded` (standard HTML form) - `application/json` (AJAX/JavaScript) - `multipart/form-data` (file uploads) **Request (JSON):** ```json { "name": "John", "email": "john@example.com", "message": "Hello!" } ``` **Response (JSON, when Accept: application/json):** ```json { "ok": true, "submissionId": "sub_001" } ``` **Response (HTML):** Shows a styled thank-you page, or redirects if `_next` field or `redirect_url` is set. **Rate Limiting:** Returns HTTP 429 when monthly submission limit is reached. **Special Fields:** - `_gotcha` — Honeypot spam protection (hidden; if filled, submission is silently accepted but not stored) - `_next` — Custom redirect URL after submission --- ### Forms #### List Forms **`GET /api/forms`** ```json { "forms": [ { "id": "abc123", "name": "Contact Form", "userId": "user_001", "emailNotify": true, "webhookUrl": null, "slackWebhookUrl": null, "discordWebhookUrl": null, "redirectUrl": null, "createdAt": "2025-01-15T10:00:00Z", "_count": { "submissions": 42 } } ] } ``` #### Create Form **`POST /api/forms`** **Request:** ```json { "name": "Contact Form", "redirectUrl": "https://yoursite.com/thanks", "emailNotify": true, "webhookUrl": "https://hooks.example.com/webhook", "slackWebhookUrl": "https://hooks.slack.com/services/...", "discordWebhookUrl": "https://discord.com/api/webhooks/..." } ``` Required fields: `name` Optional fields: `redirectUrl`, `emailNotify` (default: true), `webhookUrl`, `slackWebhookUrl`, `discordWebhookUrl` All URL fields are validated — must be valid HTTP/HTTPS URLs. **Response (201):** ```json { "form": { "id": "abc123", "name": "Contact Form", "redirectUrl": "https://yoursite.com/thanks", "emailNotify": true, "webhookUrl": "https://hooks.example.com/webhook", "slackWebhookUrl": null, "discordWebhookUrl": null, "createdAt": "2025-01-15T10:00:00Z" } } ``` **Error (403):** Form limit reached for current plan. #### Get Form **`GET /api/forms/:id`** Returns form details including submission count. ```json { "form": { "id": "abc123", "name": "Contact Form", "webhookUrl": null, "slackWebhookUrl": null, "discordWebhookUrl": null, "redirectUrl": null, "emailNotify": true, "createdAt": "2025-01-15T10:00:00Z", "_count": { "submissions": 42 } } } ``` #### Update Form **`PATCH /api/forms/:id`** **Request (all fields optional):** ```json { "name": "Updated Form", "webhookUrl": "https://hooks.slack.com/...", "slackWebhookUrl": "https://hooks.slack.com/services/...", "discordWebhookUrl": "https://discord.com/api/webhooks/...", "redirectUrl": "https://yoursite.com/thanks", "emailNotify": false } ``` **Response:** ```json { "form": { "id": "abc123", "name": "Updated Form", "webhookUrl": "https://hooks.slack.com/...", "redirectUrl": "https://yoursite.com/thanks" } } ``` #### Delete Form **`DELETE /api/forms/:id`** ```json { "ok": true } ``` --- ### Submissions #### List Submissions **`GET /api/forms/:id/submissions`** **Query Parameters:** - `page` — Page number (default: 1) - `limit` — Items per page (default: 50, max: 100) **Response:** ```json { "submissions": [ { "id": "sub_001", "formId": "abc123", "data": { "name": "John", "email": "john@example.com", "message": "Hello!" }, "files": [], "ip": "1.2.3.4", "createdAt": "2025-01-15T12:30:00Z" } ], "pagination": { "page": 1, "limit": 50, "total": 42, "pages": 1 } } ``` #### Get Submission **`GET /api/submissions/:id`** Returns a single submission with form details. #### Delete Submission **`DELETE /api/submissions/:id`** ```json { "ok": true } ``` --- ### Files #### Download File **`GET /api/submissions/:id/files/:fileId`** Returns the file content with appropriate `Content-Type` header. Supports authentication via: - `Authorization: Bearer YOUR_API_KEY` header - `?token=YOUR_API_KEY` query parameter (for direct browser downloads) File object structure (in submission `files` array): ```json { "id": "file_abc123", "name": "document.pdf", "size": 102400, "type": "application/pdf", "path": "uploads/file_abc123/document.pdf" } ``` --- ### Account #### Get Account Info **`GET /api/account`** ```json { "account": { "email": "user@example.com", "plan": "free", "limits": { "forms": 1, "submissions": 50 }, "usage": { "forms": 1, "submissions": 23 } } } ``` --- ### API Keys #### List API Keys **`GET /api/keys`** ```json { "keys": [ { "id": "key_001", "name": "Default", "formId": null, "createdAt": "2025-01-15T10:00:00Z", "lastUsedAt": "2025-01-16T08:00:00Z" } ] } ``` #### Create API Key **`POST /api/keys`** **Request:** ```json { "name": "My Key", "formId": "abc123" } ``` Both fields are optional. `formId` scopes the key to a specific form. **Response (201):** ```json { "key": "fb_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "id": "key_001", "name": "My Key", "formId": "abc123" } ``` > ⚠️ The raw API key (`key` field) is only returned once at creation time. Store it securely. #### Delete API Key **`DELETE /api/keys/:id`** ```json { "ok": true } ``` --- ## JavaScript / AJAX Examples ### Fetch API ```javascript fetch("https://api.formback.email/f/YOUR_FORM_ID", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ name: "John", email: "john@example.com", message: "Hello!" }) }) .then(res => res.json()) .then(data => console.log("Success:", data)) .catch(err => console.error("Error:", err)); ``` ### React ```jsx import { useState } from "react"; export default function ContactForm() { const [status, setStatus] = useState(""); const handleSubmit = async (e) => { e.preventDefault(); setStatus("sending"); const data = new FormData(e.target); const res = await fetch("https://api.formback.email/f/YOUR_FORM_ID", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(Object.fromEntries(data)), }); setStatus(res.ok ? "sent" : "error"); }; return (