> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://typeform.ferndocs.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://typeform.ferndocs.com/_mcp/server.

# Responses API Walkthroughs

> Learn how to retrieve, filter, and manage typeform responses using practical walkthroughs for common scenarios.

The Responses API lets you programmatically retrieve and manage responses submitted to your typeforms. You can fetch responses, filter by date or completion status, and implement compliance features like data deletion.

> **Info**
>
> These walkthroughs assume you already have your Typeform access token and know
> how to pass it in the Authorization header of your request. If you need an
> access token, go to the Get Started section first.

## Retrieve responses for a form

The most basic operation is retrieving all responses for a specific form.

### Get all responses

```bash
GET https://api.typeform.com/forms/{form_id}/responses
```

This returns a paginated list of responses with:

* Response IDs
* Submission times
* Calculated values (scores, etc.)
* All question-answer pairs

**Example response:**

```json
{
  "total_items": 150,
  "page_count": 15,
  "items": [
    {
      "landing_id": "abc123xyz",
      "token": "abc123xyz",
      "response_id": "abc123xyz",
      "landed_at": "2024-01-15T10:30:00Z",
      "submitted_at": "2024-01-15T10:35:00Z",
      "calculated": {
        "score": 85
      },
      "answers": [
        {
          "field": {
            "id": "field1",
            "type": "short_text",
            "ref": "name"
          },
          "type": "text",
          "text": "John Smith"
        }
      ]
    }
  ]
}
```

## Filter and paginate responses

Responses can be filtered by various criteria to get exactly what you need.

### Filter by date range

Get responses submitted within a specific time period:

```bash
GET https://api.typeform.com/forms/{form_id}/responses?since=2024-01-01T00:00:00Z&until=2024-01-31T23:59:59Z
```

Parameters:

* `since`: Include responses submitted after this datetime (ISO 8601 format)
* `until`: Include responses submitted before this datetime (ISO 8601 format)

### Filter by completion status

Get only completed responses:

```bash
GET https://api.typeform.com/forms/{form_id}/responses?completed=true
```

Or get partial/incomplete responses:

```bash
GET https://api.typeform.com/forms/{form_id}/responses?completed=false
```

### Paginate through responses

Control pagination with `page_size` and `before`/`after` parameters:

```bash
# Get first page (25 responses)
GET https://api.typeform.com/forms/{form_id}/responses?page_size=25

# Get next page using the last response token
GET https://api.typeform.com/forms/{form_id}/responses?page_size=25&before={last_token}
```

> **Info**
>
> The default page size is 25 responses. The maximum is 1000 per request.

### Combine filters

You can combine multiple filters:

```bash
GET https://api.typeform.com/forms/{form_id}/responses?since=2024-01-01&completed=true&page_size=50
```

## Retrieve specific responses

### Get responses by ID

Fetch a specific response using its token:

```bash
GET https://api.typeform.com/forms/{form_id}/responses?included_response_tokens={token1},{token2},{token3}
```

This is useful when you need to check specific submissions or update records in your system.

### Query specific fields

Retrieve only certain fields from responses:

```bash
GET https://api.typeform.com/forms/{form_id}/responses?fields={field_id1},{field_id2}
```

This reduces response payload size when you only need specific answers.

## Sort responses

Order responses by submission time:

```bash
# Newest first (default)
GET https://api.typeform.com/forms/{form_id}/responses?sort=submitted_at,desc

# Oldest first
GET https://api.typeform.com/forms/{form_id}/responses?sort=submitted_at,asc
```

## Handle file uploads

If your form includes file upload fields, response data includes download URLs:

```json
{
  "field": {
    "id": "file_field",
    "type": "file_upload",
    "ref": "resume"
  },
  "type": "file_url",
  "file_url": "https://api.typeform.com/forms/{form_id}/responses/{response_id}/fields/{field_id}/files/{filename}"
}
```

### Download uploaded files

To download files from responses:

```bash
GET https://api.typeform.com/forms/{form_id}/responses/files
```

This returns a list of all uploaded files with download URLs.

### Download a specific file

```bash
GET https://api.typeform.com/forms/{form_id}/responses/{response_id}/fields/{field_id}/files/{filename}
```

> **Warning**
>
> File URLs are temporary and expire after a period of time. Always download
> files promptly or store them in your own system if needed long-term.

## Working with response data

### Parse answers by type

Different field types return answers in different formats:

**Text fields:**

```json
{
  "type": "text",
  "text": "User's answer"
}
```

**Choice fields:**

```json
{
  "type": "choice",
  "choice": {
    "id": "choice_id",
    "label": "Selected option",
    "ref": "option_a"
  }
}
```

**Multiple choices:**

```json
{
  "type": "choices",
  "choices": {
    "ids": ["choice1_id", "choice2_id"],
    "labels": ["Option A", "Option B"],
    "refs": ["option_a", "option_b"]
  }
}
```

**Number fields:**

```json
{
  "type": "number",
  "number": 42
}
```

**Date fields:**

```json
{
  "type": "date",
  "date": "2024-01-15"
}
```

**Email fields:**

```json
{
  "type": "email",
  "email": "user@example.com"
}
```

**URL fields:**

```json
{
  "type": "url",
  "url": "https://example.com"
}
```

**Phone number fields:**

```json
{
  "type": "phone_number",
  "phone_number": "+1-555-0123"
}
```

**Boolean fields:**

```json
{
  "type": "boolean",
  "boolean": true
}
```

**Payment fields:**

```json
{
  "type": "payment",
  "payment": {
    "amount": "99.99",
    "currency": "USD",
    "success": true,
    "transaction_id": "ch_abc123"
  }
}
```

## Integration workflow

A typical integration workflow:

1. **Poll for new responses** periodically:

```bash
GET https://api.typeform.com/forms/{form_id}/responses?since={last_check_time}
```

2. **Process each response** in your application
3. **Store the `submitted_at` timestamp** to use as `since` parameter for next poll
4. **Handle any file downloads** needed
5. **Update your database** with the response data

### Example: Sync to database

```javascript
// Pseudocode
async function syncResponses(formId, lastSyncTime) {
  const url = `https://api.typeform.com/forms/${formId}/responses?since=${lastSyncTime}&completed=true`;

  const response = await fetch(url, {
    headers: {
      Authorization: `Bearer ${accessToken}`,
    },
  });

  const data = await response.json();

  for (const item of data.items) {
    // Process and store each response
    await saveToDatabase({
      responseId: item.response_id,
      submittedAt: item.submitted_at,
      answers: item.answers,
      score: item.calculated?.score,
    });
  }

  // Update last sync time
  if (data.items.length > 0) {
    const latestTime = data.items[0].submitted_at;
    await updateSyncTimestamp(latestTime);
  }
}
```

## Monitor response rates

Track form performance by analyzing response metadata:

```javascript
// Calculate completion rate
const landedCount = responses.filter((r) => r.landed_at).length;
const completedCount = responses.filter((r) => r.submitted_at).length;
const completionRate = (completedCount / landedCount) * 100;

// Calculate average completion time
const completionTimes = responses
  .filter((r) => r.landed_at && r.submitted_at)
  .map((r) => new Date(r.submitted_at) - new Date(r.landed_at));
const avgTime =
  completionTimes.reduce((a, b) => a + b, 0) / completionTimes.length;
```

## Best practices

1. **Use pagination**: Don't try to fetch all responses at once for forms with many submissions
2. **Implement rate limiting**: Respect API rate limits in your integration
3. **Cache responses**: Store responses locally to reduce API calls
4. **Handle errors gracefully**: Implement retry logic for failed requests
5. **Filter efficiently**: Use date filters to only fetch new responses
6. **Process asynchronously**: Handle response processing in background jobs
7. **Monitor API usage**: Track your API usage to stay within limits

## Error handling

Common scenarios to handle:

```javascript
try {
  const response = await fetchResponses(formId);

  if (response.status === 404) {
    // Form doesn't exist or you don't have access
  }

  if (response.status === 429) {
    // Rate limit exceeded - wait and retry
  }

  if (response.status === 403) {
    // Authorization issue - check your token
  }
} catch (error) {
  // Network or other errors
  console.error('Failed to fetch responses:', error);
}
```

## Next steps

* Learn about [JSON response structure](/responses-api/json-response-explanation)
* Implement [Right to be Forgotten](/responses-api/right-to-be-forgotten) for GDPR compliance
* See the [API Reference](/api-reference) for complete endpoint documentation
* Set up [Webhooks](/webhooks-api/walkthroughs) for real-time response notifications