Skip to content

Embed and submit a form on your website

Build a website form that loads Caraer’s public field definition, uploads files, and submits values into the configured records. You need a published form and its company and form UUIDs. Public form endpoints do not use your private API token; never expose a private token in a browser application.

Terminal window
curl -X GET "https://v2.api.caraer.com/api/v2/forms/public/COMPANY_UUID/FORM_UUID"

This returns a public DTO version of the form that your frontend can render.

Understand the form structure before rendering

Section titled “Understand the form structure before rendering”

The public form payload is structured, not just a flat field list. At a high level it contains:

  • object: the target Caraer object this form submits into
  • grids: ordered form sections/steps in case of a wizard otherwise just one grid
  • description: form-level helper text
  • styling: standard, underline, or plain
  • wizard: whether the form is multi-step
  • metadata: arbitrary key-value metadata
  • thankYouMessage: post-submit success message
  • redirectUrl: optional URL to redirect to after submit

Each item in grids is a section model (FormItem) with:

  • title
  • description
  • type (section or step): Sections represent an introduction or informational “slide” in the form wizard and do not contain any fields for data entry—they are used for welcome screens or instructions only. Steps, by contrast, contain the actual fields to be completed by the user.
  • grid (two-dimensional array)

The grid is important:

  • outer array = rows
  • inner array = cells in a row

Each cell (GridItem) can hold one of:

  • property (actual input field mapped to a property)
  • text (static content/instruction)
  • form (nested form)
  • submitButton (button label)
  • settings (UI and behavior options like required, placeholder, help text)

Example shape (simplified):

{
"object": { "uuid": "..." },
"wizard": true,
"grids": [
{
"title": "Personal details",
"type": "step",
"grid": [
[
{ "property": { "uuid": "prop-firstname", "name": "firstname" } },
{ "property": { "uuid": "prop-lastname", "name": "lastname" } }
],
[
{
"property": { "uuid": "prop-email", "name": "email" },
"settings": {
"required": true,
"placeholder": "you@example.com",
"helpText": "We only use this for application updates."
}
}
],
[{ "submitButton": "Submit application" }]
]
}
]
}
  • Non-wizard forms support a single grid section.
  • A form should only have one submit button in total.
  • Field validation happens on submit against property type/format rules.

Implementation checklist:

  • Build a field renderer based on form field types
  • Respect required/optional field behavior from the payload
  • For select-like fields that require dynamic options, call the public options endpoint
  • Keep field keys aligned with form property UUIDs/names expected by the API

Step 3: Upload files first (if your form has file inputs)

Section titled “Step 3: Upload files first (if your form has file inputs)”
Terminal window
curl -X POST "https://v2.api.caraer.com/api/v2/forms/public/COMPANY_UUID/FORM_UUID/upload" \
-F "files=@resume.pdf" \
-F "files=@motivation-letter.pdf"

The API returns uploaded file keys. Include those keys in the final form payload where your file fields expect them.

Terminal window
curl -X POST "https://v2.api.caraer.com/api/v2/forms/public/COMPANY_UUID/FORM_UUID/submit" \
-H "Content-Type: application/json" \
-d '{
"object": { "uuid": "..." },
"wizard": true,
"grids": [
{
"title": "Personal details",
"type": "step",
"grid": [
[
{ "property": { "uuid": "prop-firstname", "name": "firstname" }, "value": "Jane" },
{ "property": { "uuid": "prop-lastname", "name": "lastname" }, "value": "Doe" }
],
[
{
"property": { "uuid": "prop-email", "name": "email" },
"settings": {
"required": true,
"placeholder": "you@example.com",
"helpText": "We only use this for application updates."
},
"value": "jane.doe@example.com"
}
],
[{ "submitButton": "Submit application" }]
]
}
]
}'

On success, you receive a SuccessResponse containing a submission UUID.

For detailed type/format submission rules (for example semicolon-delimited multi-select/tag values, range format, structure JSON string, and date submission rules), see:

When you submit a form via the Caraer API, the payload isn’t just stored as a flat submission but is processed by the backend FormService. This service performs validation and then creates or updates actual objects (records) in your configured Caraer data model, linking the form data to your business entities.

A special case is when you want to track where or how the conversion happened—for example, relating a candidate submission to a specific web page or campaign. Caraer provides a key called conversionPageRecordUuid for this. If you include conversionPageRecordUuid in your form payload, the backend FormService will use it to create a relation between the submitted record (such as a Candidate or Lead) and the page record where the conversion originated.

To make this work in your integration:

  1. In your form submission payload, add the conversionPageRecordUuid inside the metadata object rather than at the top level. For example:
{
// ...existing form data
"metadata": {
"conversionPageRecordUuid": "THE_TARGET_PAGE_RECORD_UUID"
}
}
  1. Make sure the referenced page record UUID exists and your API token has access.
  2. Caraer will then link the submitted record to this page in the backend automatically as part of the submission.
  3. You can view or filter such relations later via the records API, using relation queries.

Note: Other relations (e.g., linking a record to a vacancy or source) work similarly—the FormService picks up relation fields from the payload or object/form definition and creates the links in the graph as part of post-processing, using the same internal service methods.

For direct manipulation and relation management outside forms, use the Records endpoints as described in the dedicated records guide.

  • Submitting files directly inside submit payload without uploading first.
  • Mismatch between frontend field keys and backend form schema.
  • Forgetting to fetch dynamic options for relation/select-like fields.
  • Flattening nested form values instead of nesting them under form.grids (see How nested forms work).

For repeating or related-record sections, continue with nested forms.