Submissions

Once a respondent submits a form, you retrieve the data through the API. This page covers how to list submissions and how to read the answers back.

Listing submissions

List the completed submissions for a form:

curl -X GET "https://app.penneo.com/collect/api/v1/forms/{formId}/submissions?limit=1000&offset=0" \
  -H "Authorization: Bearer YOUR_TOKEN"

Only completed submissions are returned. Query parameters:

ParameterDescription
limitPage size, 1–1000. Default 1000.
offsetNumber of results to skip. Default 0.
completedAfterOnly submissions completed strictly after this UTC time (ISO-8601, e.g. 2026-01-01T00:00:00Z).
completedBeforeOnly submissions completed strictly before this UTC time (ISO-8601).

The response is a page of submission summaries. Use completedAfter to fetch only the submissions completed since your last check:

{
  "items": [
    {
      "submissionId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
      "requestId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "casefileId": 12345,
      "submissionStartedAt": "2024-03-01T10:00:00Z",
      "submissionCompletedAt": "2024-03-01T10:05:32Z",
      "casefileCompletedAt": "2024-03-01T10:10:00Z"
    }
  ],
  "limit": 1000,
  "offset": 0
}

Take a submissionId from the list and fetch its full answers below.

Retrieving answers

Three endpoints return the same response shape. Use whichever ID you have.

By submission — using a submissionId from the list above:

curl -X GET https://app.penneo.com/collect/api/v1/forms/{formId}/submissions/{submissionId}/answers \
  -H "Authorization: Bearer YOUR_TOKEN"

By request — for a prefilled request, using its requestId:

curl -X GET https://app.penneo.com/collect/api/v2/forms/{formId}/requests/{requestId}/answers \
  -H "Authorization: Bearer YOUR_TOKEN"

By case file — using a casefileId:

curl -X GET https://app.penneo.com/collect/api/v1/casefiles/{casefileId}/answers \
  -H "Authorization: Bearer YOUR_TOKEN"

The form must be ACTIVE or ARCHIVED, and you must have access to it.

Response shape

The response is grouped by section. Each section and each field carries a multipleEntries flag that decides how its answers are shaped.

Single-entry (the common case)

{
  "formId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "submissionId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "requestId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "casefileId": 12345,
  "version": 1,
  "submissionStartedAt": "2024-03-01T10:00:00Z",
  "submissionCompletedAt": "2024-03-01T10:05:32Z",
  "casefileCompletedAt": "2024-03-01T10:10:00Z",
  "sections": [
    {
      "title": "Personal",
      "multipleEntries": false,
      "answers": [
        { "name": "full_name",  "label": "Full Name", "type": "TEXT",   "multipleEntries": false, "value": "Jane Smith" },
        { "name": "email",      "label": "Email",     "type": "EMAIL",  "multipleEntries": false, "value": "[email protected]" },
        { "name": "department", "label": "Department","type": "CHOICE", "multipleEntries": false, "value": ["product"] },
        { "name": "id_card",    "label": "ID Card",   "type": "FILE",   "multipleEntries": true,
          "values": [{ "filename": "id.pdf", "size": 12345, "link": "https://…signed-link…" }] }
      ]
    }
  ],
  "respondents": [
    { "fullName": "Jane Smith", "email": "[email protected]", "initiator": true,  "added": false },
    { "fullName": "John Doe",   "email": "[email protected]", "initiator": false, "added": true }
  ]
}

Multi-entry section

A multi-entry section carries instances instead of answers, one entry per submitted instance:

{
  "sections": [
    {
      "title": "Applicants",
      "multipleEntries": true,
      "instances": [
        { "answers": [{ "name": "name", "label": "Name", "type": "TEXT", "multipleEntries": false, "value": "Ada" }] },
        { "answers": [{ "name": "name", "label": "Name", "type": "TEXT", "multipleEntries": false, "value": "Grace" }] }
      ]
    }
  ]
}

Multi-entry field

A multi-entry field carries values (plural), the ordered list:

{
  "sections": [
    {
      "title": "Contact",
      "multipleEntries": false,
      "answers": [
        { "name": "phones", "label": "Phones", "type": "PHONE", "multipleEntries": true, "values": ["+4511111111", "+4522222222"] }
      ]
    }
  ]
}

Property reference

PropertyTypeDescription
formIdUUIDThe form this submission belongs to.
submissionIdUUIDThe submission's ID.
requestIdUUID or nullThe request this submission came from, if any.
casefileIdint or nullThe signed case file's ID, once generated.
versionintThe form version this submission was filled against.
submissionStartedAtISO 8601When the form was first opened.
submissionCompletedAtISO 8601 or nullWhen it was submitted. null if not yet submitted.
casefileCompletedAtISO 8601 or nullWhen the case file finished signing.
sections[].titlestringThe section's title.
sections[].multipleEntriesbooltrue when the section is multi-entry; it then carries instances.
sections[].answers[]arrayPresent when multipleEntries: false. The section's answers.
sections[].instances[].answers[]arrayPresent when multipleEntries: true. The answers for each instance.
answers[].namestringThe field's internal name.
answers[].labelstringThe field's display label.
answers[].typestringThe field type.
answers[].multipleEntriesbooltrue when the field is multi-entry; it then carries values (plural).
answers[].valuevariesPresent when multipleEntries: false. Shape depends on type (see below).
answers[].valuesarrayPresent when multipleEntries: true. The ordered list of values.
respondentsarraySigners associated with the submission, if any.
respondents[].fullNamestringThe signer's full name.
respondents[].emailstringThe signer's email.
respondents[].initiatorbooltrue if this signer initiated the request.
respondents[].addedbooltrue if this signer was added while the form was filled, rather than predefined on the form.

Value shapes by type

TypeShape (single value)
TEXTstring
EMAILstring
PHONEstring
DATEISO 8601 date string (YYYY-MM-DD)
DATETIMEISO 8601 datetime string
NUMBERJSON number
CHOICEarray of strings: the selected option value(s)
NIN{ "value": string, "countryCode": string }
BUSINESS_ID{ "value": string, "countryCode": string }
FILE{ "filename": string, "size": int, "link": string }

For multi-entry fields, each element of values has the shape above.

If submissionCompletedAt is null, the form has been opened but not submitted; sections may be empty or partial.

Errors

StatusWhen
404 Not FoundThe form, case file, or request doesn't exist, or you lack access.