Forms
Read-only access to forms and their responses. List forms, page through a form's responses, fetch a single response with its full comment context, or pull everything that changed since a timestamp — built for external dashboards, BI tools, and historical analysis.
Required scopes: read:forms for the form endpoints, read:formresponses for the response endpoints.
Endpoints
/api/open/v1/formsList forms (published by default, paginated)
/api/open/v1/forms/{id}Get a single form
/api/open/v1/forms/{id}/responsesList a form's responses (light payload, paginated)
/api/open/v1/formresponsesBulk feed of responses incl. form, comments and notes — ?since= for sync
/api/open/v1/formresponses/{id}Get a single response incl. form, comments and notes
List forms
curl "https://customer.monotree.com/api/open/v1/forms?status=published" \
-H "Authorization: Bearer mono_your_token_here"| Param | Notes |
|---|---|
status | published (default), draft, or all. |
since | Only forms created at or after this timestamp — ISO 8601, e.g. 2026-05-20T08:00:00Z (see timestamp format). |
per_page | Default 25, max 50. |
Form object
{
"data": {
"id": 12,
"title": "Maintenance Request",
"description": "Report broken equipment",
"instructions": "Fill out all fields",
"respondent_identity": "required",
"is_anonymous": false,
"is_commentable": true,
"allow_multiple_responses": true,
"is_published": true,
"published_at": "2026-05-01T08:00:00+00:00",
"groups": [
{ "id": 3, "name": "Kitchen Staff", "type": "department", "created_at": "2026-01-15T10:00:00+00:00" }
],
"responses_count": 118,
"created_at": "2026-04-28T09:00:00+00:00",
"updated_at": "2026-05-01T08:00:00+00:00"
}
}respondent_identity is required, optional, or anonymous; is_anonymous is true when identity is always anonymous. groups is the form's targeting — empty for a company-wide form.
List a form's responses
A light payload — field responses without the comment threads. Use the single response or the bulk feed for full context.
curl "https://customer.monotree.com/api/open/v1/forms/12/responses?status=done" \
-H "Authorization: Bearer mono_your_token_here"| Param | Notes |
|---|---|
status | Workflow status: todo, in_progress, done, or null (no status). |
since | Only responses created at or after this timestamp — ISO 8601, e.g. 2026-05-20T08:00:00Z (see timestamp format). |
per_page | Default 25, max 100. |
{
"data": {
"id": 4521,
"form_id": 12,
"form_title": "Maintenance Request",
"is_anonymous": false,
"status": "done",
"respondent": { "id": 42, "name": "Jane Doe", "email": "jane@example.com" },
"department": { "id": 3, "name": "Kitchen Staff", "type": "department" },
"field_responses": [
{ "value": "Freezer 2 is above temperature", "field": { "id": 7, "title": "What happened?", "type": "text" } },
{ "value": [ { "id": 21, "title": "Urgent" } ], "field": { "id": 8, "title": "Priority", "type": "choices" } }
],
"media": [
{ "id": 55, "type": "image", "mime_type": "image/jpeg", "filename": "freezer.jpg", "size": 182034, "url": "https://…/freezer.jpg", "width": 1280, "height": 960, "created_at": "2026-05-20T07:45:00+00:00" }
],
"created_at": "2026-05-20T07:45:00+00:00",
"updated_at": "2026-05-20T09:10:00+00:00"
}
}choices fields serialize their selections as { id, title } arrays; users and department_users fields as user objects. Hidden and archived responses are never returned.
Every response object (light and detail) includes media — the files uploaded with the submission. They belong to the response as a whole, not to a specific field. type is image, video or document, and url is a direct download link. On anonymous responses the files are stored encrypted, so url is a short-lived signed link (expires after ~5 minutes) — re-fetch the response whenever you need a fresh one.
Get a single response
Includes the embedded form, the shared public_comments thread, and the staff-only internal_comments — the full context for analysis.
curl https://customer.monotree.com/api/open/v1/formresponses/4521 \
-H "Authorization: Bearer mono_your_token_here"{
"data": {
"id": 4521,
"form_id": 12,
"...": "…same fields as the list payload…",
"form": { "id": 12, "title": "Maintenance Request", "...": "…full form object…" },
"public_comments": [
{
"id": 901,
"body": "Could you re-check the freezer reading?",
"form_response_id": 4521,
"form_id": 12,
"author": { "id": 5, "name": "Sam Owner", "email": "sam@example.com" },
"media": [
{ "id": 77, "type": "image", "mime_type": "image/jpeg", "filename": "freezer.jpg", "url": "https://cdn.monotree.dk/…/freezer.jpg", "width": 1200, "height": 800 }
],
"created_at": "2026-05-20T08:00:00+00:00",
"updated_at": "2026-05-20T08:00:00+00:00"
}
],
"internal_comments": [
{
"id": 33,
"body": "Escalated to facilities.",
"form_response_id": 4521,
"form_id": 12,
"author": { "id": 5, "name": "Sam Owner", "email": "sam@example.com" },
"created_at": "2026-05-20T08:05:00+00:00",
"updated_at": "2026-05-20T08:05:00+00:00"
}
]
}
}public_commentsis the thread shared with the respondent;authorisnullwhen the comment was written by the respondent on an anonymous response. Attachments arrive inmedia.internal_commentsare staff-only notes — never visible to the respondent in the app, exposed here for complete context.
Bulk feed with since
GET /formresponses returns the same detail payload as the single fetch, paginated across all forms — no need to iterate form ids. Its since parameter filters on updated_at, so one poll captures everything that happened since your last sync: new responses, field or workflow-status edits, and new public or internal comments (each bumps the response's updated_at). Results are ordered by updated_at descending.
curl "https://customer.monotree.com/api/open/v1/formresponses?since=2026-05-20T00:00:00Z" \
-H "Authorization: Bearer mono_your_token_here"| Param | Notes |
|---|---|
since | Responses created or updated at or after this timestamp — ISO 8601, e.g. 2026-05-20T08:00:00Z. Omit for a full dump (initial backfill). |
status | Workflow status: todo, in_progress, done, or null. |
per_page | Default 25, max 100. |
An invalid since or status returns 422. For push-based integration, the outgoing webhooks fire on response creation, updates, and comment activity.
The since timestamp format
Every since parameter on these endpoints takes an ISO 8601 timestamp. Always include the timezone — Z for UTC or an explicit offset:
?since=2026-05-20T08:00:00Z UTC
?since=2026-05-20T10:00:00%2B02:00 UTC+2 (a literal + must be url-encoded as %2B)
?since=2026-05-20 date only — midnight in the platform's timezoneValues without a timezone are interpreted in the platform's timezone, so send an explicit Z/offset to avoid surprises. Anything that can't be parsed as a date returns 422. When syncing, use the updated_at of the newest record you've already processed (the API returns timestamps in ISO 8601 with offset), and remember the comparison is inclusive (>=) — records exactly on the boundary appear again.