
# Retrieve uploaded files from form responses

{{<tags>}}

This guide explains **how to retrieve** files (images, PDFs, and so on) that a user uploads in a **File** form field—either **via API** or **inside a flow** (for example, to forward them on WhatsApp). For configuring the File question and client-side upload behavior, see {{< newtab href="/guides/file_input_image_uploads/" >}}Upload images using File input{{< /newtab >}} and {{< newtab href="/guides/forms/" >}}Forms{{< /newtab >}}.

## Table of contents

1. [What happens when someone uploads a file](#1-what-happens-when-someone-uploads-a-file)
2. [Get the form response](#2-get-the-form-response)
3. [Interpret the `file` field and media IDs](#3-interpret-the-file-field-and-media-ids)
4. [Resolve a media ID: metadata and download URL](#4-resolve-a-media-id-metadata-and-download-url)
5. [Important notes (expiry, security, multiple files)](#5-important-notes-expiry-security-multiple-files)
6. [Using uploads in flows: custom media integration](#6-using-uploads-in-flows-custom-media-integration)
7. [Example: form → extraction → WhatsApp](#7-example-form--extraction--whatsapp)
8. [Checklist summary](#8-checklist-summary)

## 1. What happens when someone uploads a file

In **Forms**, a **File** input lets users attach documents (images, PDF, Word, and so on, depending on field configuration). Those files are **not embedded as base64** in the form response: they are stored through the **media service**, and the form response stores **identifiers** (`MID…`) that point to those media objects.

**Conceptual flow:**

1. The user completes the form and uploads one or more files.
2. The system records the response with **media IDs** in the `values` array of the input with `type: "file"`.
3. To get name, MIME type, size, and a **signed download URL**, call the **media API** with that ID.

## 2. Get the form response

To read everything the user submitted (including file references), use the Forms responses endpoint, replacing `response_id` with the real response identifier.

**Request**

- **Method:** `GET`
- **URL:** `https://api.forms.truora.com/v1/forms/responses/{response_id}`

The response is JSON with sections, inputs, response status, timestamps, and related fields.

## 3. Interpret the `file` field and media IDs

In the JSON, walk `sections[]` → `inputs[]` until you find the input with `"type": "file"`.

Relevant fields:

{{<table "table w-auto small m-auto text-center table-striped table-bordered">}}
| Field | Meaning |
| --- | --- |
| `input_id` | Field identifier in the form |
| `label` | Label shown to the user |
| `type` | Must be `"file"` |
| `values` | Array of **strings**; each entry is a **media ID** (`MID…`) |
| `config` | Limits: `allowed_file_types`, `max_number_of_files`, `upload_method`, and so on |
{{</table>}}

**Simplified example** (illustrative structure):

```json
{
  "response_id": "FRP9c84f0954423a2c...",
  "form_id": "FORM8a6bbe2a2ad7cf40067a...",
  "client_id": "TCI8abd9a5daf7354d...",
  "version": 2,
  "sections": [
    {
      "section_id": "SEC597aa6f1ff1b4800",
      "name": "My first form",
      "inputs": [
        {
          "input_id": "IN0905170d77c76800",
          "label": "Question 1",
          "type": "file",
          "values": ["MID4e56bc0d7f92efaa5d290dc6..."],
          "required": false,
          "config": {
            "allowed_file_types": [
              "image/png",
              "application/pdf",
              "image/gif",
              "image/jpeg",
              "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
            ],
            "max_number_of_files": 1,
            "upload_method": "upload_file"
          }
        }
      ]
    }
  ],
  "response_status": "finished"
}
```

If `max_number_of_files` is greater than 1, `values` can contain **several** `MID…` entries; iterate the whole array.

## 4. Resolve a media ID: metadata and download URL

Each entry in `values` is a **media ID**. To get file metadata and a **signed URL** (S3 or equivalent), call the account media endpoint.

**Request**

- **Method:** `GET`
- **URL:** `https://flows.truora.com/account-api/v1/media/{media_id}`

Replace `{media_id}` with the full ID (for example `MID4e56bc0d7f92efaa5d290d...`).

**Typical response (useful fields):**

{{<table "table w-auto small m-auto text-center table-striped table-bordered">}}
| Field | Use |
| --- | --- |
| `media_id` | Confirms the ID |
| `name` | File name |
| `media_type` | Media category: `image`, `video`, `audio`, `document`, `sticker`, or `file` |
| `mime_type` | MIME type (for example `image/jpeg`) |
| `content_length` | Size in bytes |
| `status` | Upload or processing state |
| `url` | **Signed URL** to download the file |
| `url_expiry` | **When the URL stops being valid** |
{{</table>}}

```json
{
  "media_id": "MID4e56bc0d7f92efaa5d290...",
  "name": "f3e3c8ba-b722-4997-a8de-75610ba4f17c.jpg",
  "media_type": "file",
  "mime_type": "image/jpeg",
  "content_length": 77453,
  "status": "Uploaded",
  "url": "https://truora-files-production.s3.us-east-1.amazonaws.com/...",
  "url_expiry": "2026-03-27T20:50:41Z"
}
```

## 5. Important notes (expiry, security, multiple files)

1. **Temporary URLs**  
   The `url` field is usually a **presigned URL** with an expiry (`url_expiry`). If you need the file later, **call the media endpoint again** to obtain a fresh URL.

2. **Authentication**  
   Forms and Account API / media typically require **valid credentials** (API key, token, or your product’s auth mechanism). Set headers according to your environment’s documentation.

3. **Multiple files**  
   Iterate **all** entries in the `values` array for the `file` input, not only the first one.

4. **Allowed types**  
   `config.allowed_file_types` reflects what the form allows; `mime_type` from media confirms what was stored.

5. **Downstream processing**  
   If a pipeline (OCR, validation, and so on) needs the binary, **download** from `url` before it expires, or query media again.

## 6. Using uploads in flows: custom media integration

To **use files uploaded in a form step** inside the flow editor (for example, pass an image to WhatsApp, document extraction, and so on), you usually need a **custom integration** aimed at the **media** service.

That integration typically:

- reads flow context (form response / available media IDs), and  
- calls the media API or exposes the URL to the next block, depending on how your flow is modeled.

See your internal **custom integrations** documentation or templates for the exact connector (service name, input/output variables). For WhatsApp flows and images, {{< newtab href="/guides/integration_to_get_wa_flow_images/" >}}Use Custom Integrations to get WhatsApp flow images{{< /newtab >}} may also help.

## 7. Example: form → extraction → WhatsApp

**Goal:** the user completes a form with a file; the flow **extracts** data from the document and **sends the image** (or a message with link/file) over **WhatsApp**.

Suggested steps:

1. **Create the form** with at least one **File** input and the MIME types you need.
2. **Create the flow** and add a **form** block linked to that form.
3. Add a **custom integration** block using the **media** integration (to resolve `MID…` to a URL or whatever the flow requires internally).
4. Chain **document extraction** (or another step) if needed, using the image as configured in the product.
5. Finish with **WhatsApp** delivery (template, media, and so on, per connector capabilities).

## 8. Checklist summary

- [ ] You have the form **`response_id`**.
- [ ] You **GET** `https://api.forms.truora.com/v1/forms/responses/{response_id}`.
- [ ] You locate the input with **`type: "file"`** under `sections[].inputs[]`.
- [ ] You treat each **`values[]`** entry as a **`media_id`**.
- [ ] For each media ID you **GET** `https://flows.truora.com/account-api/v1/media/{media_id}`.
- [ ] You use **`url`** to download; you watch **`url_expiry`** and refresh when needed.
- [ ] In **flows**, you connect the **custom media integration** where the product requires it.

## Quick endpoint reference

{{<table "table w-auto small m-auto text-center table-striped table-bordered">}}
| Action | Method and path |
| --- | --- |
| Read form response | `GET https://api.forms.truora.com/v1/forms/responses/{response_id}` |
| File metadata and URL | `GET https://flows.truora.com/account-api/v1/media/{media_id}` |
{{</table>}}

Base URLs may differ by environment; confirm against your account configuration or internal documentation.
