> For the complete documentation index, see [llms.txt](https://docs.powerfulform.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.powerfulform.com/public-api/submissions.md).

# APIs for Submissions

List, filter and read the answers your forms collect, and understand every field in a submission object.

The submission endpoints are the centre of the API. This page covers reading them; the child pages cover writing.

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Create a submission</strong></td><td><code>POST /forms/{id}/submit</code></td><td><a href="/public-api/submissions/create-a-submission.md">Create a submission</a></td></tr><tr><td><strong>Update a submission</strong></td><td><code>PATCH /submissions/{id}</code></td><td><a href="/public-api/submissions/update-a-submission.md">Update a submission</a></td></tr><tr><td><strong>Delete submissions</strong></td><td><code>DELETE</code> and <code>bulk_delete</code></td><td><a href="/public-api/submissions/delete-submissions.md">Delete submissions</a></td></tr><tr><td><strong>Download a file</strong></td><td><code>GET /submissions/{id}/files/{uuid}</code></td><td><a href="/public-api/submissions/download-a-file.md">Download a file</a></td></tr></tbody></table>

Both endpoints on this page require the `submissions:read` scope.

## List submissions

```
GET /submissions
```

Returns submissions across every form in the store, newest first, unless you narrow it with the filters below.

### Query parameters

<table><thead><tr><th width="190">Parameter</th><th width="110">Type</th><th>Notes</th></tr></thead><tbody><tr><td><code>form_id</code></td><td>string</td><td>One id, or several separated by commas: <code>form_id=10,11</code>.</td></tr><tr><td><code>status</code></td><td>string</td><td><code>read</code> or <code>unread</code>.</td></tr><tr><td><code>tag</code></td><td>string</td><td>One tag name, or several separated by commas. Matches a submission carrying <strong>any</strong> of them.</td></tr><tr><td><code>created_at_min</code></td><td>date</td><td>At or after this time.</td></tr><tr><td><code>created_at_max</code></td><td>date</td><td>At or before this time. Must not be earlier than <code>created_at_min</code>.</td></tr><tr><td><code>q</code></td><td>string</td><td>Free-text search across the answers. <strong>Minimum 3 characters.</strong> An exact submission id also matches.</td></tr><tr><td><code>limit</code></td><td>integer</td><td>1–250. Defaults to 50.</td></tr><tr><td><code>cursor</code></td><td>string</td><td>The <code>next_cursor</code> from the previous page.</td></tr></tbody></table>

{% hint style="info" %}
`created_at_min` and `created_at_max` are read as **UTC**, not your store's timezone. This is deliberate — a machine-readable API should not silently shift timestamps — but it means the numbers can differ from what the **Submissions** screen shows for the same calendar day.
{% endhint %}

### Example

```bash
curl "https://app.powerfulform.com/api/public/v1/submissions?form_id=10&status=unread&created_at_min=2026-09-01&limit=100" \
  -H "X-PFB-API-KEY: pfb_your_key_here"
```

```json
{
  "data": [
    {
      "id": 101,
      "form_id": 10,
      "status": "unread",
      "content": {
        "name": "Le Thi Lan",
        "email": "lan@example.com",
        "region": "APAC",
        "source": "api"
      },
      "files": [],
      "tags": ["wholesale"],
      "notes": null,
      "customer": null,
      "ticket": null,
      "is_hidden": false,
      "hidden_reason": null,
      "created_at": "2026-09-17T02:11:40Z",
      "updated_at": "2026-09-17T02:11:40Z"
    }
  ],
  "meta": { "limit": 100, "has_next": true, "next_cursor": "eyJ0cyI6IjIwMjYtMDktMTci..." }
}
```

Keep calling with `next_cursor` until `has_next` is `false`. See [Pagination](/public-api/requests-and-responses.md#pagination).

## Get a submission

```
GET /submissions/{id}
```

Same object, one record:

```bash
curl https://app.powerfulform.com/api/public/v1/submissions/101 \
  -H "X-PFB-API-KEY: pfb_your_key_here"
```

## The submission object

<table><thead><tr><th width="180">Field</th><th>Meaning</th></tr></thead><tbody><tr><td><code>id</code></td><td>Submission id.</td></tr><tr><td><code>form_id</code></td><td>The form it was submitted to.</td></tr><tr><td><code>status</code></td><td><code>read</code> or <code>unread</code>. Change it with <a href="/public-api/submissions/update-a-submission.md">PATCH</a>.</td></tr><tr><td><code>content</code></td><td>The answers, keyed by the field <code>key</code> from <a href="/public-api/forms.md#the-field-schema">the form schema</a>. <code>null</code> when hidden — see below.</td></tr><tr><td><code>files</code></td><td>Uploaded files, each with a stable <code>download_url</code>. See <a href="/public-api/submissions/download-a-file.md">Download a file</a>.</td></tr><tr><td><code>tags</code></td><td>Tag names as an array of strings.</td></tr><tr><td><code>notes</code></td><td>The internal note, or <code>null</code>.</td></tr><tr><td><code>customer</code></td><td>The linked Shopify customer (<code>shopify_customer_id</code>, <code>email</code>), or <code>null</code>.</td></tr><tr><td><code>ticket</code></td><td>The ticket <code>number</code> and <code>name</code> when the form uses the ticket system, otherwise <code>null</code>.</td></tr><tr><td><code>is_hidden</code></td><td><code>true</code> when <code>content</code> is withheld.</td></tr><tr><td><code>hidden_reason</code></td><td>Why it is withheld, or <code>null</code>.</td></tr><tr><td><code>created_at</code> / <code>updated_at</code></td><td>ISO 8601 UTC.</td></tr></tbody></table>

### Inside `content`

`content` mirrors what the form collected, so its keys differ per form. Read `GET /forms/{id}` to map keys to labels.

Two keys are added by the system rather than typed by a person:

* `source` — `api` for submissions created through this API, so you can always separate them from storefront traffic.
* `locale` — present when the submission carried a language.

## When content is withheld

If the store has gone past a plan limit, the API says so instead of returning the data:

| `hidden_reason`    | What you get                                                                                                                  |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
| `null`             | Everything. The normal case.                                                                                                  |
| `quota_exceeded`   | `content` is `null`, `files` is empty, `is_hidden` is `true`. The submission is past the plan's monthly allowance.            |
| `storage_exceeded` | `content` still readable, but `files` is empty and attachments cannot be downloaded. The store is over its storage allowance. |

{% hint style="warning" %}
The API withholds data rather than substituting placeholder text. An integration that silently wrote sample data into your CRM would be far worse than one that stops — so check `is_hidden` before you store anything, and treat a run of hidden records as a signal to upgrade rather than as empty submissions. See [Plans and billing](/settings/plans-and-billing.md).
{% endhint %}

## Errors

<table><thead><tr><th width="120">Status</th><th width="220">Code</th><th>Cause</th></tr></thead><tbody><tr><td>403</td><td><code>insufficient_scope</code></td><td>The key is missing <code>submissions:read</code>.</td></tr><tr><td>404</td><td><code>not_found</code></td><td>No such submission, or a <code>form_id</code> in the filter belongs to another store.</td></tr><tr><td>422</td><td><code>validation_failed</code></td><td>A parameter was rejected — most often <code>q</code> shorter than 3 characters, or <code>created_at_max</code> before <code>created_at_min</code>.</td></tr></tbody></table>

<br>

## Next steps

* [Create a submission](/public-api/submissions/create-a-submission.md) — post new data into a form.
* [Update a submission](/public-api/submissions/update-a-submission.md) — tags, notes and read status.
* [Download a file](/public-api/submissions/download-a-file.md) — fetch an uploaded attachment.
* [Delete submissions](/public-api/submissions/delete-submissions.md) — remove one or many.
