Reference
Base URL https://api.formspark.io/public/v1. Every request needs an Authorization: Bearer header. The machine-readable description is at /openapi.json.
Responses contain a form's settings and its notification emails. Captcha secret keys, the Slack token and the Zapier key are never returned; they stay in the dashboard.
Token
GET /me
Describes the current token. Works with any token.
Workspaces
GET /workspaces
Every workspace you are a member of, cursor paginated. Scope: workspaces:read.
Query parameters: limit (1 to 100, default 25), startingAfter.
POST /workspaces
Scope: workspaces:write.
curl -X POST https://api.formspark.io/public/v1/workspaces \
-H "Authorization: Bearer $FORMSPARK_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Acme"}'PATCH /workspaces/{workspaceId}
Renames a workspace. Scope: workspaces:write.
Forms
GET /forms?workspaceId=...
Forms in a workspace, cursor paginated. Scope: forms:read.
Query parameters: limit (1 to 100, default 25), startingAfter.
GET /forms/{formId}
Scope: forms:read.
POST /forms
Creates a form, applying any settings sent with it. workspaceId and name are required. Scope: forms:write.
curl -X POST https://api.formspark.io/public/v1/forms \
-H "Authorization: Bearer $FORMSPARK_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"workspaceId": "your-workspace-id",
"name": "Contact",
"notificationEmails": ["you@example.com"]
}'The response contains the form's id, which is what your HTML form posts to:
<form action="https://submit-form.com/your-form-id" method="POST">
<input type="email" name="email" />
<button type="submit">Send</button>
</form>PATCH /forms/{formId}
Applies the fields present in the body. Fields you leave out keep their current value. Scope: forms:write.
curl -X PATCH https://api.formspark.io/public/v1/forms/your-form-id \
-H "Authorization: Bearer $FORMSPARK_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Contact us"}'Send null to clear a field. Send notificationEmails as the complete list you want, since it replaces the existing one.
DELETE /forms/{formId}
Deletes the form and its submissions. Scope: forms:write.
Form settings
POST /forms and PATCH /forms/{formId} accept a form's settings, with a few restrictions. Anything the API rejects comes back as a validation_error.
Beyond the three settings described below, a form carries these fields. Each of them accepts null to clear it, except name, which a form always has.
| Field | Type |
|---|---|
name | string, 128 characters |
description | string, 512 characters |
technology | string, 128 characters |
slackChannel | string, 128 characters |
customHoneypot | string, 128 characters |
customSpamWords | string, 2560 characters |
emailThreading | boolean |
customHoneypot and customSpamWords are the API side of the settings described under spam protection.
spamProtection
Accepts one of four providers, or null to require no challenge at all:
| Value | Provider |
|---|---|
BOTPOISON | Botpoison |
GOOGLE_RECAPTCHA_V2 | reCAPTCHA v2 |
HCAPTCHA | hCaptcha |
TURNSTILE | Turnstile |
No other value is accepted, and the automatic spam filtering that screens every submission is not configurable.
The provider's secret key is not part of the API. Store it in the dashboard first, then switch the form over: selecting a provider whose secret key is not already stored is rejected. See spam protection.
webhookUrl
Must be an http or https URL, and must resolve to a public address when Formspark calls it, so an endpoint on localhost or a private network is rejected. See webhooks.
notificationEmails
A form accepts at most 100 notification emails, each at most 128 characters. Since the list you send replaces the existing one, read the current list back first if you are adding to it rather than replacing it.
Submissions
GET /forms/{formId}/submissions
Newest first, cursor paginated. Scope: submissions:read.
Query parameters: limit (1 to 100, default 25), startingAfter, search.
curl "https://api.formspark.io/public/v1/forms/your-form-id/submissions?limit=50" \
-H "Authorization: Bearer $FORMSPARK_TOKEN"GET /workspaces/{workspaceId}/submissions
The same, across every form in the workspace. Scope: submissions:read.
DELETE /submissions/{submissionId}
Scope: submissions:write.
Submissions quarantined as spam expire on their own and cannot be deleted early. Deleting one returns a conflict.