Skip to content
RSFlowHub
Developer docs API v1 Stable OpenAPI SDKs Playground
Contact Forms and Newsletter Signups for Your Website

Contact Forms and Newsletter Signups

Add a contact form or a newsletter signup to any website with one script tag, or call the Forms API from your own design. Messages land in your dashboard and your inbox, with spam protection and clear limits.

New to Forms? See the Forms overview and plans, or add an AI chat widget to the same site.

What Forms is

Forms is a separate product with its own plans: you do not need an API plan, credits or a chatbot. A contact form collects messages from your visitors into an inbox you can search, answer and export. A newsletter signup collects email addresses with double opt-in (the person confirms by email). We collect and store them; you send your newsletters with your own email tool.

Plans and limits

Launch offer 20% off every Forms plan. Prices shown already include the discount.
PlanPrice / monthFormsMessages / monthStored subscribersExtras
Forms Free Free 1 50 100 Basic spam protection
Forms Starter ₹199 / $3 ₹159 / $2.40 5 1,000 1,000 AI spam check (500/mo)
Forms Pro ₹499 / $6 ₹399 / $4.80 25 10,000 10,000 AI spam check (5,000/mo) , AI tags (5,000/mo) , AI reply drafts (300/mo) , auto-reply , webhook , no “Powered by” line

Already on a paid API plan? Forms plans are 15% cheaper, applied automatically at checkout. The free plan needs no payment and no phone verification. Spam is never counted against your limit. Manage your plan from Dashboard → Billing.

Install in 4 steps

1

Create a form

Open Dashboard → Forms and choose Contact form or Newsletter signup.

2

Set it up in the Settings tab

Choose the fields (up to 8 for a contact form), the button and thank-you texts, an optional redirect, colours, a privacy checkbox, and where email alerts go.

3

Copy the code from the Install tab

It is one line and never changes, even when you change the settings later:

install-snippet.html HTML
<script src="https://rsflowhub.com/widget/v1/rsflowhub-forms.js"
        data-form-token="fm_sec_YOUR_FORM_TOKEN"
        async></script>
4

Paste it where the form should appear

The form is drawn right where the tag is. Pick your platform:

contact.html
<section>
  <h2>Contact us</h2>
  <script src="https://rsflowhub.com/widget/v1/rsflowhub-forms.js"
        data-form-token="fm_sec_YOUR_FORM_TOKEN"
        async></script>
</section>
<!-- Add a "Custom HTML" block where the form should appear, then paste: -->
<script src="https://rsflowhub.com/widget/v1/rsflowhub-forms.js"
        data-form-token="fm_sec_YOUR_FORM_TOKEN"
        async></script>
{% comment %} Online Store > Themes > Customize > Add section > Custom Liquid {% endcomment %}
<script src="https://rsflowhub.com/widget/v1/rsflowhub-forms.js"
        data-form-token="fm_sec_YOUR_FORM_TOKEN"
        async></script>
import { useEffect, useRef } from 'react';

export default function ContactForm() {
  const box = useRef(null);
  useEffect(() => {
    const s = document.createElement('script');
    s.src = 'https://rsflowhub.com/widget/v1/rsflowhub-forms.js';
    s.async = true;
    s.setAttribute('data-form-token', 'fm_sec_YOUR_FORM_TOKEN');
    box.current.appendChild(s); // the form is drawn right after the script tag
    return () => { box.current.innerHTML = ''; };
  }, []);
  return <div ref={box} />;
}
{{-- Anywhere in a Blade view --}}
<script src="https://rsflowhub.com/widget/v1/rsflowhub-forms.js"
        data-form-token="fm_sec_YOUR_FORM_TOKEN"
        async></script>

To place it inside a specific element, add data-target:

data-target.html HTML
<div id="contact-box"></div>
<script src="https://rsflowhub.com/widget/v1/rsflowhub-forms.js"
        data-form-token="fm_sec_YOUR_FORM_TOKEN"
        data-target="#contact-box"
        async></script>
The form token is public, your API key is not
The fm_sec_… token only lets visitors send messages to that one form and is meant to appear in your page source. To limit where it works, list your websites under Allowed websites in the form settings.

What the embed does

  • It lives in its own isolated box: your site's CSS cannot break it and its CSS does not touch your site. It works under a strict Content-Security-Policy (no inline styles or scripts).
  • It is accessible: every field has a label, errors are announced and focus moves to the first problem, and inputs are large enough that phones do not zoom.
  • It shows quick checks (required, valid email) while the server does the real validation.
  • When the message is sent it shows your thank-you text (or redirects to your https page) and fires a browser event you can use for analytics: document.addEventListener('rsflowhub:form-submitted', e => console.log(e.detail)) with detail.type (contact or newsletter) and detail.ref.
  • Free plans show a small “Powered by RSFlowHub” line; Forms Pro removes it.

Use the API from your own design

Looking for every endpoint, body field and answer? See the full Forms API Reference.

Build the form in your own HTML and send the fields as JSON. The token goes in the X-Form-Token header. Fields are the ones you defined in the settings, keyed by their Field ID; unknown keys are ignored. Requests from browsers must come from one of your allowed websites (if you listed any).

Send a contact message

POST https://rsflowhub.com/api/v1/forms/submissions

submit.sh Bash
curl -X POST https://rsflowhub.com/api/v1/forms/submissions \
  -H "X-Form-Token: fm_sec_YOUR_FORM_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"fields": {"name": "Ann", "email": "ann@example.com", "message": "Hello!"}, "consent": true}'

200: saved

200.json JSON
{
  "status": "success",
  "message": "Thanks! Your message has been sent.",
  "data": { "ref": "FRM-AB12CD" }
}

422: a field is invalid

422.json JSON
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "details": { "fields.email": ["The fields.email field must be a valid email address."] }
  }
}
Body fieldMeaning
fieldsObject with one value per field, keyed by Field ID (name, email, message, ...).
consenttrue when the visitor accepted your privacy notice. Required when you turned on Ask visitors to accept a privacy notice; the time is stored with the message.
websiteLeave this out (or empty). It is a hidden trap for bots: if it is filled the request is accepted but nothing is stored. Do not render it in your own form, or render it hidden.

Add a newsletter subscriber

POST https://rsflowhub.com/api/v1/forms/subscribers (newsletter forms only; the contact endpoint above is for contact forms only).

subscribe.sh Bash
curl -X POST https://rsflowhub.com/api/v1/forms/subscribers \
  -H "X-Form-Token: fm_sec_YOUR_FORM_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"fields": {"email": "reader@example.com"}, "consent": true}'

The person is stored as waiting and receives an email with a confirmation link (valid 7 days). Only after they click it do they count as a subscriber. The answer is the same for every address, new or not, so your form cannot be used to find out who is on your list.

Status codes

CodeMeaning
200Accepted. Spam is accepted too (visitors and bots see the same answer); it is kept in your Spam filter.
401Missing, wrong or paused form token.
403The request does not come from one of your allowed websites.
404Wrong endpoint for this form type.
422A field is missing or invalid. error.details maps fields.<id> to messages.
429Too many requests from one visitor, or your plan's monthly limit is reached (code is monthly_limit or subscriber_limit). The text is safe to show to visitors.

Your inbox and exports

  • Messages: filter Inbox / New / Read / Replied / Spam, search, open a message (it is marked read), reply by email, mark it replied, mark or rescue spam, delete, or export everything as CSV. You also get an email for each new message (at most 10 per hour per form; everything stays in the dashboard).
  • Subscribers: Waiting, Confirmed and Unsubscribed with search and CSV export. The CSV contains each person's permanent unsubscribe link: put it in every email you send from your own tool.
  • Spreadsheet-safe: exported cells that start with =, +, - or @ are neutralised so a visitor cannot run a formula on your computer.

Spam protection

  • On every plan: a hidden trap field for bots, a limit on how fast one visitor can send, and rules that look for many links, throwaway email domains, repeated text and common spam phrases. Messages that look like spam are kept for review (nothing is silently lost) and do not count towards your limit.
  • Starter and Pro: an optional AI second opinion on messages the rules did not flag. If the AI is unavailable or your monthly AI allowance is used up, your real messages still arrive; the helper simply pauses.

AI helpers, auto-reply and webhook

  • AI tags (Pro): each message gets a label such as sales, support or billing and a mood (positive, negative, neutral, mixed) shown in your inbox.
  • Suggested reply (Pro): a draft answer you review and send yourself. It is never sent automatically. Only the visitor's words are sent to the AI, not their email address.
  • Automatic reply (Pro): an optional “we received your message” email with your own words. One per address per day, and never containing what the visitor typed.
  • Webhook (Pro): every new message (and every confirmed subscriber) is sent to an https address you choose as a signed JSON request. Addresses on private networks are refused, redirects are not followed, and failures are retried a few times. Use Send a test event in the settings to try it.
webhook-body.json JSON
{
  "event": "form.submission.created",
  "form": { "name": "Website contact form", "type": "contact" },
  "data": {
    "ref": "FRM-AB12CD",
    "received_at": "2026-10-12T09:30:00+00:00",
    "fields": { "name": "Ann", "email": "ann@example.com", "message": "Hello!" },
    "consented_at": null
  }
}

Each request carries X-RSFlowHub-Event (form.submission.created, form.subscriber.confirmed or form.test) and X-RSFlowHub-Signature: sha256=…, the HMAC-SHA256 of the raw body with the secret shown in your form settings. Always verify it and answer with a 2xx status:

webhook.php
$body = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $body, $yourWebhookSecret);

if (! hash_equals($expected, $_SERVER['HTTP_X_RSFLOWHUB_SIGNATURE'] ?? '')) {
    http_response_code(401);
    exit;
}
// the request really came from RSFlowHub: $event = json_decode($body, true);
import crypto from 'node:crypto';

// Use the RAW request body (express.raw), not a re-serialised object.
const expected = 'sha256=' + crypto.createHmac('sha256', process.env.WEBHOOK_SECRET).update(rawBody).digest('hex');
const received = req.get('X-RSFlowHub-Signature') || '';

const ok = received.length === expected.length
  && crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));
if (!ok) return res.sendStatus(401);

Privacy and data

  • Consent: turn on the privacy checkbox and a message or signup cannot be sent without it. The time they accepted is stored.
  • Retention: choose how long messages are kept (30, 90, 180 or 365 days, or until you delete them). Older messages, and subscribers who unsubscribed longer ago than that, are deleted every night. Signups that were never confirmed are removed after 30 days whatever you choose; confirmed subscribers are never deleted automatically.
  • Access and erasure requests: on the Forms page, enter the person's email under Privacy requests, then Download their data (a JSON file) or Delete their data (messages and newsletter signups in all your forms).
  • Visitor IP addresses are never stored, only a keyed hash used to spot abuse. Text sent to your inbox is cleaned of HTML.

Troubleshooting

SymptomLikely cause and fix
Nothing appears on my pageOpen the browser console: “the form token or website is not allowed” means a wrong or regenerated token, a paused form, or your site is not in Allowed websites. An ad blocker or a Content-Security-Policy that blocks rsflowhub.com also hides it.
403 Origin not allowedAdd the site (and its www or subdomain variant) to Allowed websites, or clear the list to allow any site. Server-side or curl requests carry no Origin and are refused while a list is set; call the API from the browser, or clear the list.
Visitors see “not accepting messages right now”Your monthly message limit (or stored-subscriber limit) is used up. Upgrade from Billing; you were emailed at 80% and 100%.
No email alertsCheck Email alerts in Settings, the address, and your spam folder. At most 10 alerts per hour are sent per form; every message is still in the dashboard.
A real message went to SpamOpen the Spam filter, open the message and choose Not spam. It then counts towards your limit and is treated as a normal message.
My changes don't showSettings load on each page view. Hard-refresh, and clear any page cache or CDN in front of your site (the script and settings are fetched separately).

Forms Q&A

No. Forms has its own plans (Free, Starter and Pro) and does not use your API credits. If you also have a paid API plan, Forms plans are 15% cheaper. The Free Forms plan needs no payment and no phone verification.

Yes. Build the form in your own HTML and send the fields as JSON to the Forms API with your form token in the X-Form-Token header. The embed and the API do the same thing, with the same spam protection and limits.

Yes. The token (fm_sec_...) is public by design and is not your API key. It can only send messages to that one form, and you can restrict it to your own websites in the form settings. Never put your private API key in website code.

No. Forms collects and stores signups with double opt-in (the person confirms by email) and lets you export them as CSV, including each person's unsubscribe link. You send your newsletters with your own email tool.

New messages are turned away with a short, generic message until next month or until you upgrade, and you get an email at 80% and at 100%. Messages already received stay in your dashboard. Spam is not counted.

You choose how long messages are kept (30 days to a year, or until you delete them) and older ones are deleted every night. Newsletter signups that were never confirmed are removed after 30 days. You can also download or delete everything stored about one email address from the Forms page.

Ready to build?

Create your free account and make your first API call in minutes.

RSFlowHub

Sign in to continue

You'll come straight back to this page.

Forgot password?

New to RSFlowHub? Create a free account