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:
| Parameter | Description |
|---|---|
limit | Page size, 1–1000. Default 1000. |
offset | Number of results to skip. Default 0. |
completedAfter | Only submissions completed strictly after this UTC time (ISO-8601, e.g. 2026-01-01T00:00:00Z). |
completedBefore | Only 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
| Property | Type | Description |
|---|---|---|
formId | UUID | The form this submission belongs to. |
submissionId | UUID | The submission's ID. |
requestId | UUID or null | The request this submission came from, if any. |
casefileId | int or null | The signed case file's ID, once generated. |
version | int | The form version this submission was filled against. |
submissionStartedAt | ISO 8601 | When the form was first opened. |
submissionCompletedAt | ISO 8601 or null | When it was submitted. null if not yet submitted. |
casefileCompletedAt | ISO 8601 or null | When the case file finished signing. |
sections[].title | string | The section's title. |
sections[].multipleEntries | bool | true when the section is multi-entry; it then carries instances. |
sections[].answers[] | array | Present when multipleEntries: false. The section's answers. |
sections[].instances[].answers[] | array | Present when multipleEntries: true. The answers for each instance. |
answers[].name | string | The field's internal name. |
answers[].label | string | The field's display label. |
answers[].type | string | The field type. |
answers[].multipleEntries | bool | true when the field is multi-entry; it then carries values (plural). |
answers[].value | varies | Present when multipleEntries: false. Shape depends on type (see below). |
answers[].values | array | Present when multipleEntries: true. The ordered list of values. |
respondents | array | Signers associated with the submission, if any. |
respondents[].fullName | string | The signer's full name. |
respondents[].email | string | The signer's email. |
respondents[].initiator | bool | true if this signer initiated the request. |
respondents[].added | bool | true if this signer was added while the form was filled, rather than predefined on the form. |
Value shapes by type
| Type | Shape (single value) |
|---|---|
TEXT | string |
EMAIL | string |
PHONE | string |
DATE | ISO 8601 date string (YYYY-MM-DD) |
DATETIME | ISO 8601 datetime string |
NUMBER | JSON number |
CHOICE | array 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
submissionCompletedAtisnull, the form has been opened but not submitted;sectionsmay be empty or partial.
Errors
| Status | When |
|---|---|
404 Not Found | The form, case file, or request doesn't exist, or you lack access. |
Updated 3 days ago
