> 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/api.md).

# Overview

Read and write your forms, submissions and analytics from your own server with an API key.

The Public API lets your own code do what you would otherwise do by hand in the app: pull submissions into your CRM, push a lead in from another system, check yesterday's conversion rate, or clear out old records on a schedule.

It is a REST API. Every request carries an API key, every response is JSON, and every endpoint is scoped to the store that issued the key.

{% hint style="warning" %}
The Public API is **server-to-server only**. A request that arrives with an `Origin` header — which is every request a browser makes — is rejected with `403 cors_not_supported`. Never put an API key in JavaScript, a theme file, or a mobile app.
{% endhint %}

## What you can do

<table><thead><tr><th width="180">Area</th><th>What the API gives you</th></tr></thead><tbody><tr><td><strong>Forms</strong></td><td>List your forms and read a form's field schema, so you know the key for every answer.</td></tr><tr><td><strong>Submissions</strong></td><td>List, filter and read submissions; create new ones; edit tags, notes and read status; delete one or many; download uploaded files.</td></tr><tr><td><strong>Metrics</strong></td><td>Views, submissions and conversion rate over a date range, as a daily series, or broken down by country, device, browser and UTM source.</td></tr></tbody></table>

Form **configuration** is deliberately read-only-by-omission: there is no endpoint that edits a form. Form settings hold SMTP passwords, admin emails and integration secrets, so nothing from that config leaves the API except the field schema.

## Plan requirement

The Public API is included on **Advanced** and every plan above it — Advanced, Pro 50, Pro 100, Pro 500, Enterprise, Enterprise+, Premium 100K and Premium 200K.

On any other plan, including the paid plans below Advanced, the app will not issue a key, and a call made with an older key returns:

```json
{
  "errors": [
    {
      "code": "plan_upgrade_required",
      "message": "Your plan does not include the 'publicApi' feature. Upgrade to use the public API."
    }
  ]
}
```

Every plan that includes the API gets the same [rate-limit budget](/public-api/requests-and-responses.md#rate-limits). See [Plans and billing](/settings/plans-and-billing.md).

## Base URL

Every path in this section is relative to your store's base URL:

```
https://app.powerfulform.com/api/public/v1
```

{% hint style="info" %}
Copy the exact base URL from **Settings → Public API** in the app rather than typing it. Stores are served from more than one cluster, and calling the wrong one returns a 404 that looks like a missing endpoint.
{% endhint %}

## Endpoints

<table><thead><tr><th width="90">Method</th><th width="300">Path</th><th>Scope required</th></tr></thead><tbody><tr><td>GET</td><td><code>/ping</code></td><td>none</td></tr><tr><td>GET</td><td><code>/forms</code></td><td><code>forms:read</code></td></tr><tr><td>GET</td><td><code>/forms/{id}</code></td><td><code>forms:read</code></td></tr><tr><td>POST</td><td><code>/forms/{id}/submit</code></td><td><code>submissions:create</code></td></tr><tr><td>GET</td><td><code>/submissions</code></td><td><code>submissions:read</code></td></tr><tr><td>GET</td><td><code>/submissions/{id}</code></td><td><code>submissions:read</code></td></tr><tr><td>GET</td><td><code>/submissions/{id}/files/{uuid}</code></td><td><code>submissions:read</code></td></tr><tr><td>PATCH</td><td><code>/submissions/{id}</code></td><td><code>submissions:update</code></td></tr><tr><td>DELETE</td><td><code>/submissions/{id}</code></td><td><code>submissions:delete</code></td></tr><tr><td>POST</td><td><code>/submissions/bulk_delete</code></td><td><code>submissions:delete</code></td></tr><tr><td>GET</td><td><code>/metrics</code></td><td><code>metrics:read</code></td></tr><tr><td>GET</td><td><code>/metrics/daily</code></td><td><code>metrics:read</code></td></tr><tr><td>GET</td><td><code>/metrics/breakdown</code></td><td><code>metrics:read</code></td></tr></tbody></table>

## Versioning

The version sits in the path: `/api/public/v1`. New fields can appear in a response at any time, so parse defensively and ignore what you do not recognise. A field will never be renamed or removed from `v1` — that would ship as `v2`.

## Read next

{% columns %}
{% column %} <i class="fa-key">:key:</i> [Create an API key](/public-api/api-keys.md)

<i class="fa-rocket">:rocket:</i> [Make your first call](/public-api/quickstart.md)

<i class="fa-right-left">:right-left:</i> [Requests and responses](/public-api/requests-and-responses.md)

<i class="fa-triangle-exclamation">:triangle-exclamation:</i> [Errors](/public-api/errors.md)
{% endcolumn %}

{% column %} <i class="fa-rectangle-list">:rectangle-list:</i> [Forms](/public-api/forms.md)

<i class="fa-inbox">:inbox:</i> [Submissions](/public-api/submissions.md)

<i class="fa-chart-simple">:chart-simple:</i> [Metrics](/public-api/metrics.md)

<i class="fa-flask">:flask:</i> [API test site](/public-api/test-site.md)
{% endcolumn %}
{% endcolumns %}

<br>

## Next steps

* [Create an API key](/public-api/api-keys.md) — issue a key and choose its permissions.
* [Make your first call](/public-api/quickstart.md) — confirm the key works before you write anything real.
* [Requests and responses](/public-api/requests-and-responses.md) — headers, envelope, pagination and rate limits.
* [API test site](/public-api/test-site.md) — try every endpoint from the page, no terminal needed.
