Документация Formhook
Вставьте API-ключ в action формы, получайте отправки в панели и системное push-уведомление по каждой новой записи.
Быстрый старт
1. Зарегистрируйтесь и подтвердите почту.
2. Создайте форму в панели. Скопируйте API-ключ (выглядит как fh_…).
3. Вставьте его как action вашей HTML-формы. Готово.
HTML-форма (без JavaScript)
Самая простая интеграция. Нативная отправка формы, опциональный редирект при успехе.
<form action="https://formhook.app/f/YOUR_API_KEY" method="POST">
<input name="email" type="email" required>
<textarea name="message" required></textarea>
<!-- honeypot: bots fill this, humans don't see it -->
<input type="text" name="_gotcha" tabindex="-1" autocomplete="off"
style="position:absolute;left:-9999px">
<!-- where to send the user after success -->
<input type="hidden" name="_redirect" value="https://example.com/thanks">
<button type="submit">Send</button>
</form>JavaScript fetch
await fetch("https://formhook.app/f/YOUR_API_KEY", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
email: "user@example.com",
message: "Hello",
}),
});React-компонент
"use client";
import { useState } from "react";
export function ContactForm() {
const [status, setStatus] = useState<"idle" | "sending" | "ok" | "error">("idle");
async function onSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
setStatus("sending");
const data = Object.fromEntries(new FormData(e.currentTarget));
const res = await fetch("https://formhook.app/f/YOUR_API_KEY", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(data),
});
setStatus(res.ok ? "ok" : "error");
}
if (status === "ok") return <p>Thanks - we'll be in touch.</p>;
return (
<form onSubmit={onSubmit}>
<input name="email" type="email" required />
<textarea name="message" required />
<button disabled={status === "sending"}>Send</button>
{status === "error" && <p>Something went wrong. Try again.</p>}
</form>
);
}WordPress
Formhook - это бэкенд для форм, поэтому любая форма WordPress может отправлять в него данные. Выберите подходящий вариант:
Нативная HTML-форма
Поместите обычную форму на страницу или в блок и укажите в её action ваш endpoint. Добавьте источник вашего сайта в «Разрешённые источники» формы, чтобы принимались заявки из браузера.
<form action="https://formhook.app/f/YOUR_API_KEY" method="POST">
<input name="email" type="email" required>
<textarea name="message" required></textarea>
<input type="hidden" name="_redirect" value="https://your-site.com/thanks">
<button type="submit">Send</button>
</form>Contact Form 7
Пересылайте каждую заявку Contact Form 7 из functions.php вашей темы. Поскольку запрос идёт с вашего сервера (без браузерного Origin), авторизуйте его заголовком X-Auth-Token:
// functions.php - forward Contact Form 7 submissions to Formhook
add_action('wpcf7_before_send_mail', function ($contact_form) {
$submission = WPCF7_Submission::get_instance();
if (!$submission) return;
$data = $submission->get_posted_data();
wp_remote_post('https://formhook.app/f/YOUR_API_KEY', [
'headers' => [
'Content-Type' => 'application/json',
'X-Auth-Token' => 'YOUR_AUTH_TOKEN',
],
'body' => wp_json_encode($data),
'timeout' => 10,
]);
});Gravity Forms
Используйте официальное дополнение Webhooks для отправки на ваш endpoint или пересылайте из functions.php с тем же серверным токеном:
// functions.php - forward Gravity Forms submissions to Formhook
add_action('gform_after_submission', function ($entry, $form) {
$payload = [];
foreach ($form['fields'] as $field) {
$payload[$field->label] = rgar($entry, (string) $field->id);
}
wp_remote_post('https://formhook.app/f/YOUR_API_KEY', [
'headers' => [
'Content-Type' => 'application/json',
'X-Auth-Token' => 'YOUR_AUTH_TOKEN',
],
'body' => wp_json_encode($payload),
'timeout' => 10,
]);
}, 10, 2);Сгенерируйте токен в разделе Настройки → Аутентификация серверных запросов вашей формы. См. Источники и аутентификация о разнице между браузерными и серверными запросами.
cURL (тестирование)
Запросы с сервера на сервер (curl, серверный код) не отправляют заголовок Origin, поэтому должны аутентифицироваться заголовком X-Auth-Token. Сгенерируйте токен в разделе Настройки → Аутентификация серверных запросов вашей формы и передавайте его в каждом запросе - без него серверные запросы отклоняются.
curl -X POST https://formhook.app/f/YOUR_API_KEY \
-H "Content-Type: application/json" \
-H "X-Auth-Token: YOUR_AUTH_TOKEN" \
-d '{"email":"test@example.com","message":"hi"}'Зарезервированные поля
Эти три имени полей удаляются из сохранённого payload:
_gotcha- honeypot. Любое непустое значение возвращает 200 OK, но молча отбрасывает отправку и не расходует квоту._redirect- URL для редиректа при успехе (только form-encoded). Должен быть на источнике из allowlist формы; иначе игнорируется.cf-turnstile-response- токен Turnstile, проверяется на сервере.
CORS
Для отправок из браузера добавьте источник (схема + хост, без пути) в Разрешённые источники вашей формы в настройках. Пустой список полностью отклоняет запросы с источником браузера. Запросы с сервера на сервер (без заголовка Origin, например curl или бэкенд) должны отправлять действительный заголовок X-Auth-Token, сгенерированный в настройках формы; без токена они отклоняются.
Cloudflare Turnstile (опционально)
Включите Turnstile в настройках формы и встройте виджет в HTML:
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js"
async defer></script>
<form action="https://formhook.app/f/YOUR_API_KEY" method="POST">
<input name="email" type="email" required>
<div class="cf-turnstile" data-sitekey="YOUR_TURNSTILE_SITEKEY"></div>
<button type="submit">Send</button>
</form>Загрузка файлов (Pro и Studio)
Формы могут принимать файлы-вложения. Отправляйте с enctype="multipart/form-data"; каждое поле <input type="file"> загружается в объектное хранилище и привязывается к отправке в вашей панели. Файлы скачиваются по подписанным URL с коротким TTL из панели; ничто не доступно публично.
<!-- enctype is the important bit -->
<form action="https://formhook.app/f/YOUR_API_KEY" method="POST" enctype="multipart/form-data">
<input name="email" type="email" required>
<textarea name="message" required></textarea>
<!-- one or more file inputs; same field name = multiple files -->
<input name="attachment" type="file">
<button type="submit">Send</button>
</form>Лимит на файл: 10 МБ. Хранилище на аккаунт: 1 ГБ на Pro, 10 ГБ на Studio. Мягкие отказы: {ok: true, warnings: ["file_too_large"]} когда отдельный файл превышает лимит, ["storage_full"] когда аккаунт достиг квоты, ["files_not_configured"] если оператор не настроил объектное хранилище. В любом случае текстовая отправка сохраняется.
Studio: подготовка и передача клиентской формы
Аккаунты Studio могут создать форму для клиента и передать её. Студия настраивает и тестирует, пока владеет формой; после передачи клиент владеет формой и её отправками, а студия видит только метаданные.
- В разделе Новая форма заполните необязательное поле Email клиента. Форма помечается как клиентская (спонсорство зафиксировано), но владелец - пока вы.
- Настройте и протестируйте форму обычным образом - отправки идут в вашу панель во время тестов.
- Когда готовы, откройте Настройки формы → раздел Передача клиенту и отправьте приглашение. Форма остаётся активной и продолжает принимать отправки во время ожидания.
- Клиент получает ссылку по email, регистрируется (email авто-подтверждается через владение токеном) и нажимает Принять. С этого момента отправки идут в его панель.
После принятия вы видите форму в консоли Клиентов со статусом + месячными счётчиками. Вы больше не видите содержимое отправок и вложения - это GDPR-граница, которая выводит вас из цепочки данных клиентов. Отправки всё равно учитываются по квоте Studio (учёт идёт вверх); сам клиент может оставаться на Бесплатном, ничего не ломая.
Импорт заявок
Массово импортируйте заявки в форму из файла JSON - откройте форму в панели управления, нажмите Импорт и загрузите файл такого вида:
{
"schemaVersion": 1,
"submissions": [
{
"payload": { "email": "ada@example.com", "message": "Hello" },
"createdAt": "2025-01-02T15:04:05Z"
}
]
}Верхний уровень может быть массивом записей или объектом с массивом submissions. Каждая запись должна содержать объект payload; поле createdAt (ISO-8601) необязательно и сохраняется при наличии. Импортированные заявки помечаются как прочитанные, никогда не вызывают уведомления или webhooks и ограничены 5000 на файл (макс. 5 МБ).
Ограничения частоты и квоты
- Между всеми формами по IP: 10 запросов/минуту → 429 с
Retry-After. - На форму: 60 запросов/минуту → 429.
- Лимит размера тела: 64 КБ → 413.
- Месячная квота бесплатного тарифа: 250 отправок в скользящем 30-дневном окне. Превышение квоты по-прежнему возвращает 200 с
warnings: ["over_quota"]в теле - отправки никогда не отбрасываются молча.
Ответы об ошибках
| HTTP | код | значение |
|---|---|---|
| 200 | ok | успех |
| 302 | - | редирект на URL _redirect |
| 400 | invalid_body | битый JSON / неподдерживаемый content-type |
| 403 | origin_not_allowed | несовпадение allowlist CORS |
| 403 | turnstile_failed | токен Turnstile отсутствует/недействителен |
| 403 | account_suspended | владелец формы заблокирован |
| 404 | form_not_found | неизвестный api_key |
| 413 | body_too_large | тело > 64 КБ |
| 429 | rate_limited | включает заголовок Retry-After |
| 500 | internal_error | повторите или сообщите |
Push-уведомления (для вас, владельца формы)
Откройте панель и нажмите Включить уведомления - браузер запросит разрешение, и каждая новая отправка будет вызывать системное уведомление, даже когда вкладка закрыта. На iOS сначала установите Formhook на домашний экран (Safari 16.4+).