Forms API Reference
Three public endpoints for contact messages and newsletter signups. Authenticate with the public form token, send JSON, and get the same spam protection, limits and privacy tools as the embed.
Prefer a script tag? See the Forms guide. Plans and pricing are on the Forms page. The AI endpoints in the API catalog use a different key and credits.
Overview
| Method | Endpoint | Used for |
|---|---|---|
GET | /api/v1/forms/config | Read the form's fields, texts and colours. |
POST | /api/v1/forms/submissions | Send a contact message (contact forms). |
POST | /api/v1/forms/subscribers | Add a newsletter signup (newsletter forms). |
Base URL: https://rsflowhub.com/api/v1/forms. All bodies and answers are JSON.
Authentication and limits
- Header:
X-Form-Token: fm_sec_.... Copy it from Dashboard → Forms → your form → Install. It is public by design and only works for that one form; it is not your private API key and uses no API credits. - Allowed websites: if you restricted the form to your sites, a request must carry a matching
OriginorRefererheader (browsers add it automatically). Requests without one get403. Leave the restriction empty for server-to-server calls. - Rate limits: reading the config is limited to 60 requests per minute per IP. Sending messages or signups is limited to 5 per minute per IP and 600 per hour per form token; above that you get
429. - Plan limits: messages and stored subscribers count against your Forms plan, separate from API credits. Spam is never counted.
Get the form configuration
GET https://rsflowhub.com/api/v1/forms/config. Useful to build your own markup from the fields you defined in the dashboard. The answer is never cached and never contains plan or billing data.
curl https://rsflowhub.com/api/v1/forms/config \
-H "X-Form-Token: fm_sec_YOUR_FORM_TOKEN"
200: configuration
{
"status": "success",
"data": {
"type": "contact",
"fields": [
{ "key": "name", "label": "Name", "type": "text", "required": true, "options": [] },
{ "key": "email", "label": "Email", "type": "email", "required": true, "options": [] },
{ "key": "message", "label": "Message", "type": "textarea", "required": true, "options": [] }
],
"submitLabel": "Send message",
"successMessage": "Thanks! Your message has been sent.",
"redirectUrl": "",
"primaryColor": "#4f46e5",
"theme": "light",
"consentRequired": false,
"consentText": "I agree that my details may be stored and used to answer my request.",
"privacyUrl": "",
"branding": true
}
}
Send a contact message
POST https://rsflowhub.com/api/v1/forms/submissions. Only for contact forms; a newsletter form answers 404.
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}'
const res = await fetch('https://YOUR_DOMAIN/api/v1/forms/submissions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Form-Token': 'fm_sec_YOUR_FORM_TOKEN',
},
body: JSON.stringify({
fields: { name: 'Ann', email: 'ann@example.com', message: 'Hello!' },
consent: true,
}),
});
const body = await res.json();
if (body.status === 'success') showThanks(body.message);
| Body field | Type | Meaning |
|---|---|---|
fields | object, required | One value per field, keyed by Field ID (name, email, message, ...). Field types are text, email, tel, textarea and select. Unknown keys are dropped and HTML is stripped. |
consent | boolean | true when the visitor accepted your privacy notice. Required when the form asks for it (consentRequired in the config). |
website | string, leave out | Hidden trap for bots. If it is filled the request is accepted but nothing is stored. Do not render it in your own form. |
200: saved
{
"status": "success",
"message": "Thanks! Your message has been sent.",
"data": { "ref": "FRM-AB12CD" }
}
422: a field is invalid
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"details": { "fields.email": ["The fields.email field must be a valid email address."] }
}
}
data.ref is the message reference shown in your inbox. If the form has a redirect URL, data.redirect_url is included. Sending the same content from the same email twice within 10 minutes returns the first reference instead of storing a duplicate.
Add a newsletter subscriber
POST https://rsflowhub.com/api/v1/forms/subscribers. Only for newsletter forms; a contact form answers 404. The body is the same shape as above, with email and an optional name in fields.
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", "name": "Sam"}, "consent": true}'
200: accepted
{
"status": "success",
"message": "Thanks! Please check your email to confirm your subscription."
}
The person is stored as waiting and gets an email with a confirmation link (valid 7 days); only after they click it do they count as a subscriber. The answer is identical for a new, waiting, confirmed or unsubscribed address, so the endpoint cannot be used to find out who is on your list.
Status codes
| Code | Meaning |
|---|---|
200 | Accepted. Spam is accepted too (visitors and bots see the same answer); it is kept in your Spam filter. |
401 | Missing, wrong or paused form token. |
403 | The request does not come from one of your allowed websites. |
404 | Wrong endpoint for this form type. |
422 | A field is missing or invalid. error.details maps fields.<id> to messages. |
429 | Too many requests, or a plan limit was reached. For plan limits code is monthly_limit or subscriber_limit. |
429: plan limit reached
{
"status": "error",
"code": "monthly_limit",
"message": "This form is not accepting messages right now. Please try again later."
}
More
- Webhook payloads, auto-reply and AI helpers are described in the Forms guide.
- Privacy tools: retention, consent, export and delete by email.
- Need the AI endpoints (sentiment, intent, translation)? See the API catalog.