API Reference
The W3Forms API has one public endpoint for receiving form submissions. All form management (creating forms, access keys, webhooks, and settings) is done through the dashboard.
POST /submit
Submit form data to W3Forms. This is the only endpoint you need.
https://api.w3forms.com/submit
Request
- Method: POST (GET is not supported)
- Content-Type:
application/x-www-form-urlencoded,multipart/form-data(required for file uploads), orapplication/json
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
access_key | string | Yes | Your form's access key (prefixed w3f_) |
redirect | URL | No | Override the success redirect URL for this submission |
subject | string | No | Override the email notification subject |
from_name | string | No | Override the email sender name |
| any other field | string / file | No | Stored as submission data, included in email and webhooks |
Examples
curl -X POST "https://api.w3forms.com/submit" \
-H "Accept: application/json" \
-d "access_key=YOUR_ACCESS_KEY" \
-d "name=Ada Lovelace" \
-d "email=ada@example.com" \
-d "message=Hello!"curl -X POST "https://api.w3forms.com/submit" \
-H "Accept: application/json" \
-F "access_key=YOUR_ACCESS_KEY" \
-F "message=Hello with a file" \
-F "attachment=@./file.pdf"Response
The response format depends on the Accept header:
- With
Accept: application/json— returns a JSON response:- 200 —
{ "success": true, "message": "Form submitted successfully" } - 400 —
{ "success": false, "error": "description" }(missing key, invalid key, domain not allowed, quota exceeded) - 405 — Method not allowed (non-POST request)
- 429 — Rate limited (too many requests from this IP)
- 200 —
- Without
Accept: application/json(browser form) — returns a 303 redirect to your configured success URL, or a default W3Forms success page if no redirect is configured. On error, redirects to your error URL or shows a default error page.
Rate limits
The submission endpoint applies rate limits per IP address to prevent abuse. Normal form traffic is well within limits. If you exceed the rate limit, you receive a 429 response. Wait a few seconds before retrying.
Idempotency
W3Forms uses an idempotency guard to prevent duplicate submissions from the same user within a short window. If a visitor double-clicks the submit button or the form is submitted twice in quick succession, only the first submission is processed. This is handled automatically — no configuration needed.
Webhook delivery
For each non-spam submission, W3Forms sends a POST request to your configured webhook URL with the submission data as a JSON body. The request includes an X-W3Forms-Signature header for verification.
Signature verification
We compute HMAC-SHA256(raw_body, webhook_secret) and send the hex digest in the signature header. Verify using constant-time comparison:
import crypto from "node:crypto";
export function verifyW3FormsWebhook({ rawBody, signature, secret }) {
const expected = crypto
.createHmac("sha256", secret)
.update(rawBody, "utf8")
.digest("hex");
const a = Buffer.from(expected, "hex");
const b = Buffer.from(signature, "hex");
if (a.length !== b.length) return false;
return crypto.timingSafeEqual(a, b);
}import hmac
import hashlib
def verify_w3forms_webhook(raw_body: bytes, signature_hex: str, secret: str) -> bool:
expected = hmac.new(secret.encode("utf-8"), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature_hex)For complete setup instructions, see Webhooks.
Dashboard API
Forms, submissions, and settings are managed via the dashboard and its authenticated API. The dashboard API uses JWT authentication (HS256, 7-day expiry) and supports CRUD operations on forms, access keys, webhook configurations, and submissions.
Use the dashboard for management. Use POST /submit for receiving form submissions from your website visitors.