Mountly

Documentation

Guides and public API reference

Public API

OpenAPI 1.0.0

Reference for the Mountly public API

Use the public API to manage forms and form entries around the static websites you already own. Read the authored sections first, then use the generated endpoint reference as the exact contract.

Base URL

https://api.mountly.io

Endpoints

7

Groups

2

Version

1.0.0

Make your first call

Start with one small request

The fastest path is one endpoint, one cURL request, and one confirmed response before you build anything larger.

  1. Read Authentication if the endpoint is protected.
  2. Check Conventions so shared schemas and response shapes are predictable.
  3. Start with GET /entries once the token is ready.

0 public endpoints and 7 protected endpoints are currently published.

Open raw OpenAPI spec

Overview

Get started

The Mountly public API is for teams that already understand their form workflow and now need a reliable contract for code. You can use it to read forms and entries outside the dashboard, move accepted submissions into other systems, or build internal tools that operate on Mountly data without going through the UI.

The key distinction is this: the guides explain how Mountly should fit into your workflow, while the API reference tells your software exactly what to send and what it will get back. If the operational path is still fuzzy, the guides are usually the better starting point. If the workflow is clear and you are ready to implement it, this page is the handoff.

Begin with one narrow request

The best first API call is usually small and read-only. Listing forms or reading entries for a single form teaches more than scaffolding a full integration before you have seen a real response. You learn the shape of the payload, confirm the environment you are targeting, and remove a lot of uncertainty before any downstream work begins.

That is also why it helps to gather only the essentials before you start: the server URL for the Mountly environment you are targeting, a bearer token if the endpoint is protected, and one specific job you want the first request to accomplish.

Read the authored sections before you rely on the generated contract

This page has two layers. The authored sections explain the rules that apply across the API, such as authentication, shared conventions, and error handling. The generated reference below them is the exact contract: endpoints, parameters, request bodies, shared schemas, and response shapes taken from the OpenAPI document.

In practice, most teams move through those layers in order. First, read the short authored sections so the general rules are clear. Then use the generated reference for the endpoint you want to implement. If your tooling can import machine-readable contracts directly, the raw OpenAPI document is the next step after that.

A good first milestone is deliberately modest

You do not need a finished integration to make meaningful progress. One successful request, one real response, and one clear next step are enough to confirm that the contract makes sense for your workflow.

From there, the sequence is straightforward: read Authentication if the endpoint is protected, continue to Conventions so shared fields behave the way you expect, and use Error handling to decide what your client should fix, surface, or retry.

Auth

Authentication

Some Mountly endpoints are public, while others require a bearer token. When a request is protected, send the token in the Authorization header:

Authorization: Bearer <access_token>

Authentication is not just a header requirement. It is part of the trust boundary around your integration, so the most important decisions happen before the request is ever sent: which workspace issued the token, what the token is meant to do, where it will be stored, and who is responsible for replacing it when that becomes necessary.

Keep tokens on trusted infrastructure

For most integrations, the safe default is simple: store the token outside source control, keep it in environment variables or a secret manager, and send protected requests from trusted server-side code. Long-lived credentials do not belong in browser-delivered code or other untrusted clients.

That approach does two things at once. It reduces the chance of accidental exposure, and it keeps the integration model clear for the next person who has to maintain it.

Issue tokens with a narrow purpose

The easiest integrations to understand are the ones where a token has one obvious job. A token might exist to read form entries for a sync process, power an internal reporting tool, or feed accepted submissions into a single downstream system. That narrow scope makes the integration easier to reason about and limits the blast radius if the credential ever needs to be rotated or revoked.

If a teammate asks what a token is for, the answer should fit in a sentence. When that answer is vague, the integration usually becomes harder to own over time.

Rotate and retire credentials deliberately

Tokens tend to outlive the original setup work, so it helps to manage them as part of the workflow rather than as a one-time configuration step. Rotate them when ownership changes, revoke them when an integration is retired, and replace them immediately if you suspect they were exposed.

It is also worth keeping a simple record of which integration depends on which token. That small habit prevents the common situation where a team inherits long-lived credentials that nobody feels confident touching.

What to do next

Once authentication is in place, continue with Conventions. That section explains the shared request and response patterns your client should preserve, including JSON bodies, timestamps, and pagination metadata.

Conventions

Conventions

The Mountly public API is easier to implement when you treat it as one consistent contract rather than a collection of unrelated endpoints. The same payload shapes, timestamp rules, and pagination patterns appear across the API, so a little consistency in your client code goes a long way.

Expect JSON bodies and date-time fields

Request and response bodies are JSON. Timestamps such as createdAt and updatedAt are exposed as date-time strings, which means your client should treat them as machine-readable values rather than presentation text.

That sounds minor, but it affects a lot of downstream behavior. If a client flattens timestamps into display strings too early, bugs tend to show up later in sorting, exports, filtering, or comparisons between systems.

Preserve pagination metadata when it appears

List endpoints may include pagination metadata, and that metadata is part of the contract rather than decoration. Fields such as currentPage, pageSize, pageCount, totalEntries, hasNextPage, and hasPreviousPage tell your client how much data exists, where the current slice sits, and whether another request is needed.

FieldWhat it tells you
currentPageThe current page of results. This value is 1-based.
pageSize and pageCountHow large each page is and how many pages exist.
totalEntriesThe total number of items across the full result set.
hasNextPage and hasPreviousPageWhether you should expect another request in either direction.

If you are building exports, dashboards, or sync jobs, preserving those fields will make the client much more reliable than trying to reconstruct pagination state from guesses.

Reuse shared schemas instead of remapping everything locally

Forms, form entries, and common error envelopes appear in more than one place throughout the API. The generated reference keeps those shared schemas visible so your client can model them once and reuse them across reads, writes, and follow-up processing.

That approach usually leads to cleaner integrations. Instead of hardcoding slightly different versions of the same object in multiple places, you end up with one stable understanding of the data shape and far fewer subtle mismatches later.

Good defaults for a new client

When you are starting fresh, a few habits make the implementation easier to extend. Begin with a read-only request before you add writes. Let the generated reference drive field names and request shapes. Preserve pagination metadata whenever the API returns it. Model shared objects as reusable types rather than one-off mappings scattered through the codebase.

Those are modest choices, but they keep the client closer to the published contract and make later changes much less painful.

What to do next

Continue with Error handling so you can decide which failures should be surfaced, which require changes to the request, and which may be worth retrying.

Errors

Error handling

Mountly returns structured error responses so your client can react to the kind of failure it received instead of treating every non-success the same way. That structure matters because an expired credential, a malformed payload, and a temporary backend issue do not deserve the same response from your code or your team.

Learn the two shared error shapes first

Two response shapes appear most often in practice:

SchemaWhen you will usually see it
ProblemDetailsGeneral API failures such as access issues or other non-validation errors.
HttpValidationProblemDetailsRequests whose payload or field values fail validation.

When you need exact field names, the generated schemas below are the source of truth. At a higher level, though, it is enough to remember that Mountly separates general failures from validation failures so your client can handle them differently.

Respond to failures by category

The most useful first distinction is not between status codes, but between classes of problems.

Error typeWhat it usually meansWhat to do next
Authentication or access errorsThe token is missing, expired, or does not have the required permission.Fix the credential or permission problem rather than retrying blindly.
Validation errorsThe request body does not match what the endpoint accepts.Surface the field-level issue, correct the payload, and send a new request.
Transient transport or service failuresA temporary network or backend condition interrupted the request.Log the failure and retry only if the condition is likely to clear.

Once your client makes that distinction, error handling becomes much more predictable. Teams can fix the actual problem instead of lumping every failure into a generic retry loop.

Treat validation failures as actionable feedback

Validation errors are usually the easiest ones to improve because the API is telling you exactly what is wrong with the input. Read the errors object, surface the field-level detail where the team or user can act on it, and correct the payload before trying again.

Retrying the same invalid request rarely helps. The productive response is to change the data, not to repeat the call.

Log for debugging without leaking secrets

When a request fails, your logs should make the failure understandable without exposing sensitive information. Capture which endpoint failed, which workflow or integration sent the request, and whether the problem looked like access, validation, or a likely transient condition. Include enough context to reproduce the issue safely, but avoid logging tokens or sensitive payload data unless it has already been redacted.

If someone can diagnose a problem from the logs without opening a secret store or replaying the entire workflow from memory, the error handling is already doing useful work.

What to do next

Use the generated schemas below when you need the exact structure of general and validation error responses, and handle them differently in code so the next step is clear whenever a request fails.

ProblemDetailsProblemDetails

Fields

typenullable

string

titlenullable

string

statusnullable

integer

detailnullable

string

instancenullable

string

extensions

Record<string, unknown>

API endpoints

Endpoint reference

Form Entries

3 endpoints

GET/entries_listFormEntries

List form entries

List form-entries from a specific form using basic pagination.

Access

Bearer token required

Request

No request body

Success

200

Parameters

3 parameters

Parameters

id

string

pageNumber

integer

pageSize

integer

Responses

3 responses

200
application/jsonListFormEntriesResponse

Fields

entries

FormEntry[]

metadata

PaginationMetadata

Related models
FormEntryFormEntry

Fields

id

string

formId

string

data

Record<string, string>

createdAt

string (date-time)

updatedAt

string (date-time)

PaginationMetadataPaginationMetadata

Contains pagination metadata

Fields

currentPage

integer

The current 1-index based page index. First page is one (1) not zero (0)!

pageSize

integer

The amount of records on this page.

pageCount

integer

Total available of pages

totalEntries

integer

Total available records

isLastPage

boolean

Indicates if this is the last page or not

isFirstPage

boolean

Indicates if this is the first page or not

hasNextPage

boolean

Indicates whether a next page is available or not

hasPreviousPage

boolean

Indicates whether a previous page is available or not

401
404

cURL

bash
curl --request GET \
  --url 'https://api.mountly.io/entries?id=<id>&pageNumber=<pageNumber>&pageSize=<pageSize>' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <token>'

200 response

json
{
  "entries": [
    null
  ],
  "metadata": {
    "currentPage": null,
    "pageSize": null,
    "pageCount": null,
    "totalEntries": null,
    "isLastPage": null,
    "isFirstPage": null,
    "hasNextPage": null,
    "hasPreviousPage": null
  }
}
PATCH/entries_updateFormEntry

Update a form entry

Update the content of a single form-entry.

Access

Bearer token required

Request

application/json required

Success

200

Parameters

No path or query parameters

Request body

1 content type

application/jsonUpdateFormEntryrequired

Request for updating a form entry

Fields

formId

string

The ID of the form to update

formEntryId

string

ID of the form-entry to update

data

Record<string, string>

Updated form-entry data, cannot be empty or null

Responses

4 responses

200
400
application/jsonProblemDetails

Fields

typenullable

string

titlenullable

string

statusnullable

integer

detailnullable

string

instancenullable

string

extensions

Record<string, unknown>

401
404

cURL

bash
curl --request PATCH \
  --url 'https://api.mountly.io/entries' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "formId": "<string>",
    "formEntryId": "<string>",
    "data": {
      "key": "<string>"
    }
  }'

UpdateFormEntry example

json
{
  "formId": "<string>",
  "formEntryId": "<string>",
  "data": {
    "key": "<string>"
  }
}

400 response

json
{
  "key": null
}
DELETE/entries_deleteFormEntry

Delete form entries

Allows deletion of selected form-entries from a form.

Access

Bearer token required

Request

application/json required

Success

200

Parameters

No path or query parameters

Request body

1 content type

application/jsonDeleteFormEntryrequired

Request for deleting a defined set of form-entries.

Fields

id

string

The ID of the form to delete entries from

formEntryIds

string[]

Array of form-entry IDs to be deleted

Responses

4 responses

200
400
application/jsonProblemDetails

Fields

typenullable

string

titlenullable

string

statusnullable

integer

detailnullable

string

instancenullable

string

extensions

Record<string, unknown>

401
404

cURL

bash
curl --request DELETE \
  --url 'https://api.mountly.io/entries' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "id": "<string>",
    "formEntryIds": [
      "<string>"
    ]
  }'

DeleteFormEntry example

json
{
  "id": "<string>",
  "formEntryIds": [
    "<string>"
  ]
}

400 response

json
{
  "key": null
}

Forms

4 endpoints

GET/forms_listForms

List forms

List all forms owned by the authenticated user.

Access

Bearer token required

Request

No request body

Success

200

Parameters

No path or query parameters

Responses

2 responses

200
application/jsonListFormsResponse

Fields

forms

Form[]

Related models
FormForm

Fields

id

string

ownerId

string

name

string

descriptionnullable

string

redirectUrlnullable

string

notificationSettings

FormNotificationSettings

acceptedSubmissionCount

integer

state

FormState

createdAt

string (date-time)

FormNotificationSettingsFormNotificationSettings

Fields

mode

FormNotificationMode

submissionIntervalnullable

integer

recipientEmailnullable

string

FormStateFormState

Represents the current forms state

401

cURL

bash
curl --request GET \
  --url 'https://api.mountly.io/forms' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <token>'

200 response

json
{
  "forms": [
    null
  ]
}
POST/forms_createForm

Create a form

Create a new form for the authenticated user.

Access

Bearer token required

Request

application/json required

Success

200

Parameters

No path or query parameters

Request body

1 content type

application/jsonCreateFormrequired

Fields

name

string

redirectUrlnullable

string

descriptionnullable

string

notificationModenullable

FormNotificationMode

notificationSubmissionIntervalnullable

integer

notificationRecipientEmailnullable

string

Related models
FormNotificationModeFormNotificationMode

Responses

4 responses

200
application/jsonCreateFormResponse

Fields

form

Form

Related models
FormForm

Fields

id

string

ownerId

string

name

string

descriptionnullable

string

redirectUrlnullable

string

notificationSettings

FormNotificationSettings

acceptedSubmissionCount

integer

state

FormState

createdAt

string (date-time)

FormNotificationSettingsFormNotificationSettings

Fields

mode

FormNotificationMode

submissionIntervalnullable

integer

recipientEmailnullable

string

FormStateFormState

Represents the current forms state

400
application/jsonProblemDetails

Fields

typenullable

string

titlenullable

string

statusnullable

integer

detailnullable

string

instancenullable

string

extensions

Record<string, unknown>

401
403

cURL

bash
curl --request POST \
  --url 'https://api.mountly.io/forms' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "name": "<string>",
    "redirectUrl": "<string>",
    "description": "<string>",
    "notificationMode": null,
    "notificationSubmissionInterval": 123,
    "notificationRecipientEmail": "<string>"
  }'

CreateForm example

json
{
  "name": "<string>",
  "redirectUrl": "<string>",
  "description": "<string>",
  "notificationMode": null,
  "notificationSubmissionInterval": 123,
  "notificationRecipientEmail": "<string>"
}

200 response

json
{
  "form": {
    "id": null,
    "ownerId": null,
    "name": null,
    "description": null,
    "redirectUrl": null,
    "notificationSettings": null,
    "acceptedSubmissionCount": null,
    "state": null,
    "createdAt": null
  }
}
PATCH/forms_updateForm

Update a form

Update a form owned by the authenticated user.

Access

Bearer token required

Request

application/json required

Success

200

Parameters

No path or query parameters

Request body

1 content type

application/jsonUpdateFormrequired

Fields

id

string

name

string

redirectUrlnullable

string

descriptionnullable

string

notificationMode

FormNotificationMode

notificationSubmissionIntervalnullable

integer

notificationRecipientEmailnullable

string

Related models
FormNotificationModeFormNotificationMode

Responses

4 responses

200
application/jsonUpdateFormResponse

Fields

form

Form

Related models
FormForm

Fields

id

string

ownerId

string

name

string

descriptionnullable

string

redirectUrlnullable

string

notificationSettings

FormNotificationSettings

acceptedSubmissionCount

integer

state

FormState

createdAt

string (date-time)

FormNotificationSettingsFormNotificationSettings

Fields

mode

FormNotificationMode

submissionIntervalnullable

integer

recipientEmailnullable

string

FormStateFormState

Represents the current forms state

400
application/jsonProblemDetails

Fields

typenullable

string

titlenullable

string

statusnullable

integer

detailnullable

string

instancenullable

string

extensions

Record<string, unknown>

401
404

cURL

bash
curl --request PATCH \
  --url 'https://api.mountly.io/forms' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "id": "<string>",
    "name": "<string>",
    "redirectUrl": "<string>",
    "description": "<string>",
    "notificationMode": "Disabled",
    "notificationSubmissionInterval": 123,
    "notificationRecipientEmail": "<string>"
  }'

UpdateForm example

json
{
  "id": "<string>",
  "name": "<string>",
  "redirectUrl": "<string>",
  "description": "<string>",
  "notificationMode": "Disabled",
  "notificationSubmissionInterval": 123,
  "notificationRecipientEmail": "<string>"
}

200 response

json
{
  "form": {
    "id": null,
    "ownerId": null,
    "name": null,
    "description": null,
    "redirectUrl": null,
    "notificationSettings": null,
    "acceptedSubmissionCount": null,
    "state": null,
    "createdAt": null
  }
}
DELETE/forms_deleteForm

Delete a formy

Delete a form owned by the authenticated user.

Access

Bearer token required

Request

application/json required

Success

200

Parameters

No path or query parameters

Request body

1 content type

application/jsonDeleteFormrequired

Fields

id

string

Responses

4 responses

200
400
application/jsonProblemDetails

Fields

typenullable

string

titlenullable

string

statusnullable

integer

detailnullable

string

instancenullable

string

extensions

Record<string, unknown>

401
404

cURL

bash
curl --request DELETE \
  --url 'https://api.mountly.io/forms' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data-raw '{
    "id": "<string>"
  }'

DeleteForm example

json
{
  "id": "<string>"
}

400 response

json
{
  "key": null
}