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), or application/json

Request fields

FieldTypeRequiredDescription
access_keystringYesYour form's access key (prefixed w3f_)
redirectURLNoOverride the success redirect URL for this submission
subjectstringNoOverride the email notification subject
from_namestringNoOverride the email sender name
any other fieldstring / fileNoStored as submission data, included in email and webhooks

Examples

curl — URL-encoded
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 — multipart (files)
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)
  • 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:

verify.node.js
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);
}
verify.python.py
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.

Back to Documentation