Перейти к содержимому
FFormhook

Документация 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 могут создать форму для клиента и передать её. Студия настраивает и тестирует, пока владеет формой; после передачи клиент владеет формой и её отправками, а студия видит только метаданные.

  1. В разделе Новая форма заполните необязательное поле Email клиента. Форма помечается как клиентская (спонсорство зафиксировано), но владелец - пока вы.
  2. Настройте и протестируйте форму обычным образом - отправки идут в вашу панель во время тестов.
  3. Когда готовы, откройте Настройки формы → раздел Передача клиенту и отправьте приглашение. Форма остаётся активной и продолжает принимать отправки во время ожидания.
  4. Клиент получает ссылку по 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кодзначение
200okуспех
302-редирект на URL _redirect
400invalid_bodyбитый JSON / неподдерживаемый content-type
403origin_not_allowedнесовпадение allowlist CORS
403turnstile_failedтокен Turnstile отсутствует/недействителен
403account_suspendedвладелец формы заблокирован
404form_not_foundнеизвестный api_key
413body_too_largeтело > 64 КБ
429rate_limitedвключает заголовок Retry-After
500internal_errorповторите или сообщите

Push-уведомления (для вас, владельца формы)

Откройте панель и нажмите Включить уведомления - браузер запросит разрешение, и каждая новая отправка будет вызывать системное уведомление, даже когда вкладка закрыта. На iOS сначала установите Formhook на домашний экран (Safari 16.4+).