Used by the script. The script calls this endpoint on its own, once for the forms found in the page, then once per batch of forms added later — see How forms are loaded. You only need it to build your own interface.
GET /api/websites/{website}/forms/config
Returns, for each requested form, its definition already translated into the language the server picked, with the settings of its link to the website.
| Check | Value |
|---|---|
| Authentication | none; the page's Origin is authoritative |
| Origin | the Origin header must match the website's host |
| Rate limiting | api-forms-config, 60 per minute per IP |
| Cache | Cache-Control: public, max-age=300, must-revalidate, ETag, Vary: Origin |
Path parameters
| Name | Type | Purpose |
|---|---|---|
website |
UUID | The website the page belongs to |
Query parameters
| Name | Required | Value |
|---|---|---|
f |
yes | Comma-separated entries slug~lang, 20 at most. slug: letters, digits, - and _; lang: a base language in lowercase (fr, en), or empty (contact~) to let the server choose |
The script sends the entries deduplicated and sorted, with the language reduced to its
base (en-GB → en): identical pages share the same cached response.
Language of each form
- The requested language, if the form offers it.
- Otherwise, when the requested language is empty or not one of the seven languages of the platform, the website language, if the form offers it.
- Otherwise the form's source language.
A language of the platform that the form does not offer gives the source language — the same rule as for a submission, see Languages.
Response 200
One key per requested entry, as sent. null for a form that does not exist, is disabled,
or is not linked to this website.
{
"forms": {
"contact~fr": {
"slug": "contact",
"locale": "fr",
"submit_button_text": "Envoyer",
"fields": [{
"name": "email",
"label": "Adresse email",
"type": "email",
"is_required": true,
"show_label": true,
"is_multiple": false,
"placeholder": null,
"help_text": null,
"link_url": null,
"options": [],
"attributes": { "maxlength": "255" },
"visibility": null
}],
"privacy_notice": { "text": null, "url": "https://www.example.com/privacy" },
"css_selector": null,
"injection_position": "inside",
"html_wrapper": null,
"appearance": { "--rk-form-accent": "#16a34a" }
},
"quote~en": null
}
}
Each form has the shape described in What the script publishes:
every text is in the language given by locale, untranslated texts falling back on the
source language one by one. The confirmation message and the recipients are never
returned; addresses are http or https only.
Response 304
A request carrying an If-None-Match equal to the current ETag receives a 304 with no
body. A change to a form, one of its translations or its link to the website changes the
ETag: with the 5-minute cache, it reaches visitors within 5 minutes.
Errors
| Code | Body | Cause |
|---|---|---|
403 |
{"error":"origin_not_allowed", …} |
The Origin does not match the website |
403 |
{"message":"This website is disabled."} |
The client's account is suspended |
404 |
{"message":"Website not found."} |
Unknown website |
422 |
Laravel validation format | f missing, more than 20 entries, or a malformed entry |
429 |
— | Rate limit exceeded — see Rate limiting |
API