# forms.app API

## Overview

The **forms.app API** gives you programmatic, read-only access to your forms and their
submissions. You can list all the forms in your account, fetch a specific form's complete
structure (questions, design settings, submission behaviour, thank-you pages), and page
through the answers your respondents have submitted.

## Authentication

Every request must be authenticated with exactly **one** of the two methods below.
Providing both in the same request is not allowed and will return `401 Unauthorized`.

### Option 1 — OAuth 2.0 Bearer Token

Obtain a JWT via the forms.app OAuth 2.0 flow and pass it in the `Authorization` header:

```
Authorization: Bearer <your_token>
```

### Option 2 — API Key

Pass your API key in the `X-Api-Key` header:

```
X-Api-Key: <your_api_key>
```

#### How to create an API key

1. Log in to [forms.app](https://forms.app).
2. Click your avatar in the top-right corner and open **Account Settings**.
3. Go to the **API Keys** tab.
4. Click **Create API Key**, enter a descriptive name, and confirm.
5. Copy the generated key immediately — it is shown **only once**.
6. Store it securely (e.g. in an environment variable or secret manager).

> You can create multiple keys (one per integration), and revoke any of them at any time
> from the same **API Keys** settings page.

## Response Envelope

All endpoints return a consistent JSON envelope:

**Success (`2xx`)**
```json
{
  "success": true,
  "data": { },
  "errors": []
}
```

**Error (`4xx` / `5xx`)**
```json
{
  "success": false,
  "data": null,
  "errors": [
    { "errorCode": 1001, "errorMessage": "Unauthorized" }
  ]
}
```

## Rate Limiting

Requests are rate-limited per API key / token. When the limit is exceeded the API returns
`429 Too Many Requests`. Wait briefly and retry — do not spam the endpoint in a tight loop.


Version: 1.0.0
License: Proprietary

## Servers

```
https://api.forms.city
```

## Security

### BearerAuth

OAuth 2.0 Bearer token (HS256 JWT) issued by the forms.app OAuth 2.0 flow.

Pass the token in the `Authorization` header:
```
Authorization: Bearer <your_token>
```

**Cannot be combined with `X-Api-Key`** — use one or the other per request.


Type: http
Scheme: bearer
Bearer Format: JWT

### ApiKeyAuth

API key generated from your forms.app account settings.

Pass the key in the `X-Api-Key` header:
```
X-Api-Key: <your_api_key>
```

**How to create an API key:**
1. Log in to [forms.app](https://forms.app).
2. Open **Account Settings** → **API Keys**.
3. Click **Create API Key**, give it a name, and copy the key.
   The key is shown **only once** — store it securely.

**Cannot be combined with `Authorization: Bearer`** — use one or the other per request.


Type: apiKey
In: header
Name: X-Api-Key

## Download OpenAPI description

[forms.app API](https://forms-app-developers.redocly.app/_bundle/apis/index.yaml)

## Form

Read-only access to forms in your account. A form is the central resource — it contains
an ordered list of questions (each with its own type, settings, and optional choices),
visual design settings (colours, fonts, theme), behavioural settings (captcha, drafts,
multi-page steps), logo configuration, and one or more thank-you pages shown after
submission. Use these endpoints to inspect form structure and sync it with external systems.


### List all forms

 - [GET /v1/form](https://forms-app-developers.redocly.app/apis/form/getuserforms.md): Returns a list of all forms that belong to the authenticated account.

Each item in the returned array contains the form's unique identifier (_id) and its
title. Use _id with the GET /form/{id} endpoint to retrieve the full structure of
a specific form including questions, design, and settings.

Forms are returned regardless of their visibility state (public, unlisted, or
private) as long as they belong to the authenticated user and are not in the trash
or archived.

### Get form by ID

 - [GET /v1/form/{id}](https://forms-app-developers.redocly.app/apis/form/getformbyid.md): Returns the complete structure of a single form identified by its _id.

The response includes everything needed to understand or reproduce the form:

- questions — ordered list of all questions, each with its type (questionType),
  label, description, required flag, and type-specific settings (choice options, text
  constraints, file upload limits, etc.).
- baseSettings — behavioural settings: captcha, draft saving, multi-step navigation,
  multiple-submission prevention, and more.
- designSettings — visual theme: colours (background, question, answer, border, main),
  font family and size, border radius, background image, and theme name.
- logo — logo image URL, alignment, brightness, and sticky behaviour.
- thankYouPages — one or more thank-you screens shown after submission, including
  redirect configuration, sharing options, and statistics display.
- submitButton — label text and alignment of the submission button.
- state — visibility of the form: public, unlisted, or private.
- supportedLanguages — language codes the form is available in.
- calculators / conditions — scoring calculator rules and conditional logic (raw arrays).
- createDate / updateDate — ISO 8601 timestamps of creation and last modification.

Returns 404 Not Found if the form does not exist or belongs to a different account.

## Answer

Read submitted answers (responses) for a form. Because a form can accumulate thousands of
submissions, answers are returned in pages. Each page contains a `result` array of answer
objects, a `totalCount` of all submissions, and a `searchAfter` cursor you pass as the next
`pageNumber` to continue walking through the full result set. Each answer captures the
respondent's replies to every question, optional file attachments, user info, scoring points,
and submission metadata such as creation date.


### List form answers (paginated)

 - [GET /v1/form/{id}/answer/p/{pageNumber}](https://forms-app-developers.redocly.app/apis/answer/listformanswersbypage.md): Returns one page of submitted answers for the specified form. Because a form can
accumulate a large number of submissions, results are delivered in pages.

Pagination flow:
1. Call with pageNumber: 1 to get the first page.
2. The response contains totalCount (total number of submissions) and a searchAfter
   cursor array that points to the last record in the current page.
3. Increment pageNumber by 1 for each subsequent request. The searchAfter cursor
   in the response can be used for cursor-based navigation in advanced scenarios.
   Repeat until you have fetched all pages (compare collected count against totalCount).

Each answer object contains:
- answers — array of per-question replies. Each entry uses short-hand field names:
  q (question ID), t (text), n (number), d (date), b (boolean),
  c (choice selections with text t, value v, and order o),
  fn (name fields: first, last, middle, prefix, suffix),
  a (address fields: line 1, line 2, city, state, postal code, country),
  ph (phone: country code, area, number, extension),
  f (uploaded files: file ID, type, size), ac (acceptance).
- userInfo — optional respondent info (full name) if collected.
- point — total score (tp) when the form uses a calculator / quiz scoring.
- answerFiles — metadata for files attached to the submission.
- fileToken — token used to download file attachments.
- publicId — public-facing submission identifier.
- createDate — ISO 8601 timestamp of when the answer was submitted.

Returns 404 Not Found if the form does not exist or belongs to a different account.

## Gateway

Gateway-level operational endpoints. These reflect the health and status of the API
gateway itself rather than any backend service. No authentication is required.


### Gateway health check

 - [GET /__health](https://forms-app-developers.redocly.app/apis/gateway/gatewayhealth.md): Returns the operational status of the API gateway (KrakenD) itself.
Use this endpoint for infrastructure liveness probes and uptime monitoring.

This is a KrakenD built-in endpoint — it reflects the gateway process status,
not any upstream backend service. Authentication is not required.

