# Fetching submissions

This tutorial shows how to retrieve submitted answers for a form using paginated requests.

## Prerequisites

- An [API key](/guides/quickstart#step-1-create-an-api-key)
- A form `_id` from [Fetching forms](/guides/tutorials/fetching-forms)


All examples use the base URL `https://api.forms.app` and the `X-Api-Key` header.

## Endpoint overview

Submissions are returned in pages:

```
GET /v1/form/{id}/answer/p/{pageNumber}
```

| Parameter | Description |
|  --- | --- |
| `id` | Form `_id` |
| `pageNumber` | Page to retrieve, starts at `1`, increment by `1` for each next page |


Because a form can have thousands of submissions, the API delivers results in pages rather than all at once.

## Fetch the first page

Replace `FORM_ID` with your form's `_id`:

```bash
curl -s https://api.forms.app/v1/form/FORM_ID/answer/p/1 \
  -H "X-Api-Key: YOUR_API_KEY"
```

### Response structure

```json
{
  "success": true,
  "data": {
    "totalCount": 142,
    "result": [
      {
        "answers": [
          {
            "q": "q1",
            "t": "Jane Doe"
          }
        ],
        "createDate": "2024-06-15T09:30:00.000Z",
        "publicId": "abc123"
      }
    ],
    "searchAfter": [1718443800000]
  },
  "errors": []
}
```

| Field | Description |
|  --- | --- |
| `totalCount` | Total number of submissions for this form |
| `result` | Array of answer objects on this page |
| `searchAfter` | Cursor pointing to the last record on this page |


## Walk through all pages

Follow this flow to collect every submission:

1. Request page `1`.
2. Process each item in `data.result`.
3. Increment `pageNumber` and request the next page.
4. Stop when you have collected `totalCount` records, or when `result` is empty.


### Example loop (pseudocode)

```javascript
const formId = "FORM_ID";
const apiKey = process.env.FORMS_APP_API_KEY;
let pageNumber = 1;
let collected = 0;
let totalCount = Infinity;

while (collected < totalCount) {
  const response = await fetch(
    `https://api.forms.app/v1/form/${formId}/answer/p/${pageNumber}`,
    { headers: { "X-Api-Key": apiKey } }
  );
  const body = await response.json();

  if (!body.success) {
    throw new Error(body.errors[0]?.errorMessage ?? "Request failed");
  }

  totalCount = body.data.totalCount;
  const page = body.data.result;

  if (page.length === 0) break;

  for (const answer of page) {
    // Process each submission
    console.log(answer.createDate, answer.answers);
  }

  collected += page.length;
  pageNumber += 1;
}
```

Rate limits
When syncing large forms, add a short delay between page requests to avoid hitting [rate limits](/guides/the-essentials#rate-limiting).

## Understanding answer objects

Each item in `result` represents one submission:

| Field | Description |
|  --- | --- |
| `answers` | Per-question replies (see below) |
| `userInfo` | Optional respondent info (for example, full name) |
| `point` | Total score when the form uses calculator / quiz scoring |
| `answerFiles` | Metadata for file attachments |
| `fileToken` | Token to download attached files |
| `publicId` | Public-facing submission identifier |
| `createDate` | ISO 8601 timestamp of when the answer was submitted |


### Answer field shorthand

Each entry in the `answers` array uses short field names:

| Field | Meaning |
|  --- | --- |
| `q` | Question ID (matches the question `_id` from the form) |
| `t` | Text value |
| `n` | Number value |
| `d` | Date value |
| `b` | Boolean value |
| `c` | Choice selections (with text, value, and order) |
| `fn` | Name fields (first, last, middle, prefix, suffix) |
| `a` | Address fields |
| `ph` | Phone fields |
| `f` | Uploaded files |
| `ac` | Acceptance (for example, terms checkbox) |


Match `q` values against question IDs from [Fetching forms](/guides/tutorials/fetching-forms) to interpret each reply.

## Error handling

| Status | Cause |
|  --- | --- |
| `401` | Invalid or missing API key |
| `404` | Form does not exist or belongs to another account |
| `429` | Rate limit exceeded, wait and retry |


## Typical integration pattern

1. Fetch the form structure to map question IDs to labels.
2. Page through all submissions on a schedule (for example, every 15 minutes).
3. Track the last synced `createDate` or page to avoid reprocessing.
4. Store answers in your database or forward them to another system.


## What's next?

- [Fetching forms](/guides/tutorials/fetching-forms)
- [API reference](/apis)
- [Frequently asked questions](/guides/faq)