Form submissions
Every form has two public endpoints: one that describes the form, and one that turns a submission into a case. The embed snippet and the hosted page use them, and you can call them yourself: from your own frontend (browser mode) or from your backend with a signed request (server mode). Building forms and their security settings is described in forms; this page is the reference for the requests.
frm_… below is the form's public id, shown on the form's page with Copy ID. The Embed tab shows the
examples on this page with your form's address and fields filled in.
The form definition
GET /api/v1/forms/frm_…/definition?locale=en
No authentication. Used by browser mode to render the form and get a start token:
{
"publicId": "frm_…",
"name": "Website contact form",
"locale": "en",
"askName": true,
"askSubject": true,
"fields": [{ "key": "message", "type": "long_text", "label": { "en": "How can we help?" }, "required": true }],
"honeypot": true,
"turnstileSiteKey": "0x4AAAA…",
"startToken": "smk3pz.9f2c…",
"successMessage": "Thank you. We have received your request.",
"paused": false,
"brand": { "name": "Example", "logoUrl": "…", "primaryColor": "#18181b", … },
"submitUrl": "https://support.example.com/api/v1/forms/frm_…/submissions"
}
turnstileSiteKey is null when the form has no Turnstile check or the installation has no Turnstile keys yet;
startToken is null when it has no minimum fill time.
It answers with an error when:
| Status | Code | When |
|---|---|---|
| 404 | not_found | The form is unknown. |
| 403 | form_disabled | The form is turned off. |
| 403 | browser_mode_disabled | The form only accepts server mode. |
| 403 | origin_not_allowed | The request comes from a website that isn't allowed. |
Lookup fields (a service)
A Service field is a field of type lookup with a source (itsm.service,
from Service Configuration) and ownAccount (true by default: only what the contact's account uses). The
definition carries lookupUrl; ask it what the field offers:
GET /api/v1/forms/frm_…/lookup/<key>?q=vpn
{ "items": [{ "id": "…", "label": "Customer VPN" }], "signIn": false }
signIn is true (and items empty) when the field is limited to the contact's account and nobody is signed in.
A field like that is left out of the definition when nobody is signed in (an embedded form, say); in server mode
the account is the one of the contact named in contact.email.
Send the picked item's id as the field's answer. The desk then:
- checks it may be picked (422
validation_failedwhen not); - keeps the name in the case's answers;
- gives the case the service before automations run.
A form on a portal works the same, at GET /api/v1/portals/<slug>/items/<entryId>/lookup/<key>?q=, where
<entryId> is the form's place on that portal (the last part of its address there, /p/<slug>/<entryId>).
In this section
- Submitting and errors: The request, the answers, rate limits and errors.
- Browser mode and server mode: From a web page with protection, or signed from your server.