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

# Make your first call

Confirm your API key works, find a form and its field keys, then create your first submission.

Three requests take you from a fresh API key to a submission created by your own code. Run them from a terminal before you write any integration — each one fails in a way that tells you exactly what is wrong.

{% hint style="info" %}
Prefer clicking to typing? The [API test site](/public-api/test-site.md) runs these same calls from the page.
{% endhint %}

## Step 1 — Check the key with `/ping`

`/ping` needs no scope. It answers with the store the key belongs to, the cluster it is served from, and the permissions the key carries.

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

```json
{
  "data": {
    "api_version": "v1",
    "cluster": "us1",
    "server_time": "2026-09-18T09:14:03Z",
    "shop": {
      "url": "your-store.myshopify.com",
      "domain": "your-store.com",
      "name": "Your Store",
      "plan": "PREMIUM"
    },
    "key": {
      "id": 42,
      "name": "Zapier production",
      "key_last4": "8f2c",
      "scopes": ["forms:read", "submissions:read", "submissions:create"],
      "last_used_at": null,
      "expires_at": null,
      "created_at": "2026-09-18T09:02:41Z"
    }
  }
}
```

Read the `scopes` array carefully — a missing scope here is the reason the next call will return 403.

<table><thead><tr><th width="230">If you get</th><th>Then</th></tr></thead><tbody><tr><td><code>401 unauthorized</code></td><td>No key reached the server. Check the header name.</td></tr><tr><td><code>401 invalid_api_key</code></td><td>The key is mistyped, revoked or expired. Issue a new one.</td></tr><tr><td><code>403 plan_upgrade_required</code></td><td>The store is on a plan below <strong>Advanced</strong>. See <a href="/settings/plans-and-billing.md">Plans and billing</a>.</td></tr><tr><td><code>403 cors_not_supported</code></td><td>Something sent an <code>Origin</code> header. You are calling from a browser.</td></tr><tr><td><code>404</code> on a valid path</td><td>Wrong base URL. Copy it from <strong>Settings → Public API</strong>.</td></tr></tbody></table>

## Step 2 — Find a form and its field keys

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

```json
{
  "data": [
    {
      "id": 10,
      "title": "Wholesale enquiry",
      "status": 1,
      "form_type": "normalForm",
      "submission_count": 214,
      "created_at": "2026-08-02T04:11:09Z",
      "updated_at": "2026-09-16T02:40:55Z"
    }
  ],
  "meta": { "limit": 50, "has_next": false, "next_cursor": null }
}
```

Take the `id` and ask for the field schema. The `key` of each field is what you send when you create a submission:

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

```json
{
  "data": {
    "id": 10,
    "title": "Wholesale enquiry",
    "status": 1,
    "field_count": 3,
    "fields": [
      { "key": "name",   "type": "text",   "label": "Full name", "required": true },
      { "key": "email",  "type": "email",  "label": "Email",     "required": true },
      { "key": "region", "type": "select", "label": "Region",    "required": true,
        "options": ["APAC", "EMEA"] }
    ]
  }
}
```

## Step 3 — Create a submission

Send the field keys from step 2 inside `data`:

```bash
curl -X POST https://app.powerfulform.com/api/public/v1/forms/10/submit \
  -H "X-PFB-API-KEY: pfb_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
        "data": {
          "name": "Tran Minh Khoa",
          "email": "khoa@example.com",
          "region": "APAC"
        }
      }'
```

A `201` comes back with the stored submission, including the id you can use for every later call.

{% hint style="info" %}
`Content-Type: application/json` is required on any request with a body. Without it the body is read as form data, `data` looks empty, and you get *The data field is required* while staring at a request that clearly has one.
{% endhint %}

This goes through the same path as a real storefront submission: it is validated against the form, it counts toward your monthly submissions, it triggers your notification emails and integrations, and it can create a Shopify customer. [Create a submission](/public-api/submissions/create-a-submission.md) covers the switches for turning those off.

## Step 4 — Read it back

```bash
curl "https://app.powerfulform.com/api/public/v1/submissions?form_id=10&limit=5" \
  -H "X-PFB-API-KEY: pfb_your_key_here"
```

Submissions created through the API are tagged `"source": "api"` inside `content`, so you can always tell them apart from ones a customer filled in.

<br>

## Next steps

* [Requests and responses](/public-api/requests-and-responses.md) — pagination, rate limits and the response envelope.
* [Submissions](/public-api/submissions.md) — every read and write operation on submissions.
* [API test site](/public-api/test-site.md) — try the rest of the endpoints without writing a client.
* [Errors](/public-api/errors.md) — the full list of error codes.
