Form submissions API
Every form you build in agencms is reachable through a public HTTP endpoint. This lets you collect submissions from your published site, a custom front end, or your own integration without using the built-in form block. This page explains the endpoint, the payload it expects, and how file uploads work.
The endpoint
Send submissions with a POST request:
POST /api/forms/{slug}/submit
Replace {slug} with your form's slug. The form must be Published before it will accept submissions. If it is in draft or any other status, the endpoint returns a 422 with the message "This form is not accepting submissions."
The endpoint is rate limited to 10 requests per minute per IP.
Telling agencms which website the form belongs to
If you call the endpoint from your live site (the site's own domain or subdomain), the website is detected automatically. If you call it from somewhere else, add a website query parameter set to the website's slug or custom domain:
POST /api/forms/contact-us/submit?website=acme-co
Request payload
Send a JSON body with these keys:
| Key | Type | Required | What it holds |
|---|---|---|---|
data |
object | Yes | A map of field name to value, one entry per form field. |
extra_data |
object | No | Optional extra metadata you want stored alongside the submission. |
file_tokens |
object | No | A map of file-upload field name to the token returned by the upload endpoint. |
locale |
string | No | The locale the visitor submitted in, for multilingual sites. |
_hp_field |
string | No | Honeypot field. Leave empty; if filled, the submission is silently dropped. |
A simple example:
{
"data": {
"name": "Jane Doe",
"email": "jane@example.com",
"message": "Hello!"
}
}
The keys inside data must match the field names defined on the form. Unknown keys are rejected. The values are validated against each field's rules (required, email format, length, allowed select options, and so on). See Forms for how field names are set.
extra_data is capped at 25 entries, with keys up to 100 characters and string values up to 1000 characters.
File uploads
File fields use a two-step flow. You upload each file first, then reference it in your submission by token.
-
POST the file to the upload endpoint:
POST /api/forms/uploadSend it as
multipart/form-datawith these fields:file— the file itselfform_slug— your form's slugfield_name— the name of the file-upload fieldfield_id— optional, the field's ID
Add the same
?website=...query parameter if needed. This endpoint is rate limited to 20 requests per minute. -
The response returns a
token, along withfilename,size, andextension:{ "token": "5f9c...", "filename": "resume.pdf", "size": 18234, "extension": "pdf" } -
Include the token in your submission under
file_tokens, keyed by the field name:{ "data": { "name": "Jane Doe" }, "file_tokens": { "resume": "5f9c..." } }
Allowed file types and size limits come from the field's settings. Executable and script file types are always blocked.
Successful response
A successful submission returns:
{
"success": true,
"message": "Thank you for your submission!",
"redirect": null,
"download": null
}
The message reflects the form's configured success message (localized when a locale was sent). If the form is set up to redirect or to serve a download after submission, those values appear in redirect and download. After a successful POST, agencms stores the submission and runs the form's handlers (such as notification emails). View collected entries on the Form submissions page.
Errors
422with a message — the form is not published, or the payload failed validation. Validation errors follow Laravel's standard shape, with messages keyed by field (for exampledata.email).404— no published form matches the slug for the resolved website.