# Accessing Submissions

There are generally two ways of accessing submissions:

1. Through the UI.
2. Through the API.

There are a number of interfaces that can be used to examine and export the submission data of a form. These are as follows.

## Accessing Submissions though the Data tab

Form submissions can be seen by clicking on the **Data** tab on a form within the Developer Portal:

<figure><img src="https://3305536326-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MPHoF2HwOA0s5HV_AIB%2Fuploads%2FdCqLJWQ1MBfBHzp1m2fq%2Fimportdata1.jpg?alt=media&#x26;token=249d64c1-0c4d-4c89-9d8c-5891f05d5019" alt=""><figcaption></figcaption></figure>

This is best treated as a form administrator or form developer review tool. Submissions containing many fields are not easy to review in the table view, and some field types may not display all the data captured in this view.

The Submissions page provides an administrative overview of submissions to a form.

The Data tab's table only displays the fields that had “Table view” selected on them. To add or remove fields from this display, edit the field on the Form Edit page and uncheck “Table View.”

![Table View configuration found within the Display tab of the component settings](https://3305536326-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MPHoF2HwOA0s5HV_AIB%2Fuploads%2FeWsERaVDBjJKa9EbuHJj%2Fimportdata1.1.jpg?alt=media\&token=28331b90-a394-4e84-9d11-b263ae59340a)

Developer Portal users with sufficient permissions can view, edit and delete individual submissions to forms. Use the icons on the right to perform these actions.

## Exporting Submission Data

Use the two **Export** buttons at the top of the submissions list to export all of the submission data for the given form. These operations are streamlined directly from the database and will work on very large datasets without having to write everything out to the server before starting the download.

### **Export JSON**

JSON (Javascript Object Notation) is a way of representing data in a standardized way for javascript applications. Many other programming languages and tools can read JSON as well. Since data in Form.io is stored in JSON format, this will be the truest form of the data.

### **Export CSV**

CSV (Comma Separated Values) is another way of representing data. Data is squashed down to rows of values with commas between them. This may not work well for complex data structures as it is essentially a flat file. CSV files can be opened by spreadsheet applications like Excel.

## Accessing Submissions through the API

Submissions data can be easily accessed via the API. This allows submission data to be used elsewhere within the application, other places in the Form.io platform, or by entirely separate services within the customer environment.

&#x20;The API provides many powerful and flexible ways to submit, collect, migrate, modify, or otherwise handle submission data.

For more detailed information, refer to the Form.io API reference:

{% embed url="<https://apidocs.form.io/#9fe90026-dd4b-a344-62e9-c7a67f0ebbb7>" %}

### Temporary Tokens

To maintain security, API calls require some kind of authentication. This can take the form of passing JWT tokens in the header, invoking admin keys configured in the deployed environment, or generating temporary tokens.

**Temporary tokens** are short-lived and usually scoped to a limited purpose. Users will typically generate the token and then use it to make the desired call.

#### Example: Using Temporary Tokens to Download Submission as PDF

To understand this, consider a user who wants to download a PDF of an individual submission. To do so, they would use the following two calls:

1. GET a temporary download token:<br>

   ```html
   GET {{projectUrl}}/token
   ```

Headers:

<table><thead><tr><th width="113.390625" align="center">Key</th><th width="675.73828125" align="center">Value</th></tr></thead><tbody><tr><td align="center">x-allow</td><td align="center">GET:/project/{{projectId}}/form/{{formID}}/submission/{{submissionID}}/download</td></tr><tr><td align="center">x-expire</td><td align="center">3600</td></tr><tr><td align="center">x-jwt-token</td><td align="center">&#x3C;Retrieved through the browser's Developer Tools > Storage > Local Store > formioToken></td></tr></tbody></table>

{% hint style="info" %}
Note how the **x-allow** key limits the scope of the token to a specific project, form, and submission. Using a token issued with this scope on a different endpoint will result in an error.&#x20;
{% endhint %}

2. GET a download of the PDF:

```
GET {{projectUrl}}/form/{{formID}}/submission/{{submissionID}}/download?token={{tempToken}}
```

Where {{tempToken}} is the key (**not** the "token")  contained in the body of the reply to the first call.

#### Walkthrough:

Consider a Developer Portal at <http://localhost:3000>.

From the Developer Portal Home, navigating to **Doc Team Project > Doc Test Form > Data** shows the Submission the user wishes to download as a PDF.

Selecting the Submission and clicking **View** shows the submission at <http://localhost:3000/#/project/2468abc/form/1369def/submission/7777ghi>

The **Live Stage** link shows as <http://localhost:3000/qwertasdf>

<figure><img src="https://3305536326-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MPHoF2HwOA0s5HV_AIB%2Fuploads%2F1hZOUuJfsIQoZZ9by7cJ%2FSubmissionDownloadSM2.png?alt=media&#x26;token=ef7f63a5-a93e-4e31-8406-ae998fd311a3" alt="" width="375"><figcaption></figcaption></figure>

Observe the following:

* The **projectURL** is *<http://localhost:3000/qwertasdf>*
* The **projectID** is *2468abc*
* The **formID** is *1369def*
* The **submissionID** is *7777ghi*

Suppose the user found via **Tools > Developer Tools** **> Storaage > Local Storage** that

* The **formioToken** is *1z1y2x35w81v32u1* (in practice it will be significantly longer)

The user would use their preferred API tool (such as Postman) to send the following request:

```html
GET http://localhost:3000/qwertasdf/token
```

<table><thead><tr><th width="109.73046875" align="center">Key</th><th align="center">Value</th></tr></thead><tbody><tr><td align="center">x-allow</td><td align="center">GET:/project/<em>2468abc</em>/form/<em>1369def</em>/submission/<em>7777ghi</em>/download</td></tr><tr><td align="center">x-expire</td><td align="center">3600</td></tr><tr><td align="center">x-jwt-token</td><td align="center"><em>1z1y2x35w81v32u1</em></td></tr></tbody></table>

{% hint style="info" %}
Note how the **x-allow** key's values set the scope of the temporary token the user will receive, attaching it to a specific project, form, and submission.
{% endhint %}

When this is successful, the body of the return will contain both the **x-jwt-token** submitted by the user as well as a **"key"** required to issue subsequent calls:

<figure><img src="https://3305536326-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MPHoF2HwOA0s5HV_AIB%2Fuploads%2FvCdZJNkVxUOz50j5cqEj%2FPostManTempTokenSM.png?alt=media&#x26;token=4129843a-5f2f-42c6-bd79-37ab79a0b261" alt=""><figcaption><p>A Postman request for a temporary token.</p></figcaption></figure>

The user would record the **key** value (*GZZFpJsyYQTWoKCdPJOyYfKRZj2GBW*) for use in the second request.

Next the user would make the following request:

<pre><code><strong>GET http://localhost:3000/project/2468abc/form/1369def/submission/7777ghi/download?token=1z1y2x35w81v32u1
</strong></code></pre>

Note that the endpoint mirrors the scope set in the previous requests x-allow value.

For this call, the **key** from the previous call is supplied as the parameter by appending\
&#x20;`?token=GZZFpJsyYQTWoKCdPJOyYfKRZj2GBW` to the request.

This will return the PDF of the submission, accessed with the temporary token.&#x20;

<figure><img src="https://3305536326-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MPHoF2HwOA0s5HV_AIB%2Fuploads%2FZNebCOW75EgkesCrCwrv%2FGetPDFSm.png?alt=media&#x26;token=7bba2580-c8ce-4fce-8906-cbba82b68e48" alt=""><figcaption><p>The returned PDF</p></figcaption></figure>

The same process is used for a variety of calls requiring temporary tokens.&#x20;

{% hint style="warning" %}
**Troubleshooting**: The most common errors when attempting to use a temporary token to make an API request are **400** and **440**, which may both be reported as "Expired token."\
To resolve these, first ensure the jwt-token used to generate the temporary token is still valid and entered in its entirety.\
Next, ensure the that the scope of the temporary token matches that required of the intended request. A malformed **x-allow** header may still return a temporary token, but if the requested scope is mis-matched to the second request, it will appear expired.\
Finally, ensure the download request uses the **key** returned when requesting the temporary token.
{% endhint %}
