API REFERENCE · Published 2026-10-06 · Updated 2026-10-06 · SecureSMTP
Submit a form
POST /api/v1/forms/submit
POSThttps://securessmtp.com/api/v1/forms/submit
Stores one form submission and emails it to up to three addresses. It also runs the spam checks and can send an auto-reply to the person who filled in the form. Call it from your server, not from the browser.
Headers
- x-securessmtp-api-keystringrequired
- The site’s API key (
qcs_live_…).x-securesmtp-api-keyandx-qcs-api-keyare accepted too. See Sites and API keys. - Content-Typestringrequired
application/json
Body
Unknown fields are ignored.
- form_idintegerrequired
- A positive whole number you choose to identify the form, e.g.
1. It is stored with the submission. It is not the ID of a hosted form (those are UUIDs). - fieldsobjectoptional
- The submitted values as
{ "field_name": "value" }. Every value must be a string, up to 10,000 characters. Default{}. The notification email shows each key as a label (underscores become spaces). - form_namestringoptional
- Up to 200 characters. Shown in the notification email and the dashboard.
- templatestringoptional
- Up to 50 characters. A label stored with the submission.
- notify_emailsstring[]optional
- Up to 10 items. Where to send the notification. Invalid and duplicate addresses are dropped and the first 3 valid ones are used.
- notify_emailstringoptional
- One address. Used only when
notify_emailsgives no valid address. If neither is set, the site’s default notification address is used. - from_namestringoptional
- Up to 120 characters. Sender name of the notification. Default: the site’s default From name, then the site name.
- visitorobjectoptional
- About the person who submitted:
ip(up to 64 characters),user_agent(up to 500),referrer(up to 500). All optional. Withoutip, the IP block and rate limit are skipped. - captcha_tokenstringoptional
- Up to 6,000 characters. The token from the captcha widget (the value of its
response_field, see GET /sites/captcha). It is checked with the provider set for the site. - cf_turnstile_tokenstringoptional
- Up to 4,000 characters. Older name for
captcha_token; used whencaptcha_tokenis empty. - captcha_provider'shared' | 'turnstile' | 'hcaptcha' | 'recaptcha' | 'recaptcha_v3' | 'none'optional
- Accepted but not used: the provider saved for the site always decides.
- confirmobjectoptional
- Auto-reply to the submitter:
enabled(boolean, defaultfalse)subject(string, up to 200 characters; defaultThanks — <site name>)body(string, HTML, up to 20,000 characters)from_name(string, up to 120 characters; default: the notification’s sender name)
{name},{email},{form_name},{site_name},{site_domain},{field:KEY}. Field values are HTML-escaped in the body. - site_urlstringoptional
- If sent, it must be a full URL (e.g.
https://acme.example). Not used otherwise.
Request
curl -X POST https://securessmtp.com/api/v1/forms/submit \
-H "x-securessmtp-api-key: $SECURESSMTP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"form_id": 1,
"form_name": "Contact",
"fields": {
"name": "Jane Doe",
"email": "[email protected]",
"message": "Do you ship to Canada?"
},
"notify_emails": [
"[email protected]"
],
"visitor": {
"ip": "203.0.113.7",
"user_agent": "Mozilla/5.0",
"referrer": "https://acme.example/contact"
},
"captcha_token": "0.Zt3x...",
"confirm": {
"enabled": true,
"subject": "Thanks, {name}",
"body": "<p>Hi {name}, we got your message and will reply soon.</p>"
}
}'Response
200
{
"ok": true,
"id": "8b1e2f4a-6c3d-4e5f-9a0b-1c2d3e4f5a6b",
"email_sent": true
}Response fields
- okbooleanrequired
truefor every accepted request, including the silent rejections below.- idstringoptional
- ID of the stored submission (UUID). Missing when
blockedistrue. - email_sentbooleanoptional
- Whether the notification email was sent. Missing when the submission was judged spam.
- blockedbooleanoptional
truewhen the submission was rejected and not stored.
Other 200 answers
These look like success on purpose, so a bot learns nothing. Your page should show its normal thank-you message for all of them.
| Body | What happened |
|---|---|
{ "ok": true, "blocked": true } | Not stored. The captcha provider rejected the token, or the visitor IP is blocked, or the IP already has more than 3 submissions in the last 60 seconds (that IP is then blocked for 1 hour). |
{ "ok": true, "id": "…" } | Stored, but the content scored as spam, so no email was sent. |
{ "ok": true, "id": "…", "email_sent": false } | Stored, but no email was sent: the account reached its monthly form-submission limit, or the email failed. |
Errors
Errors have an error field and no ok field.
| HTTP | Value | Meaning | What to do |
|---|---|---|---|
| 401 | missing_api_key | No key header was sent. | Send the key in the x-securessmtp-api-key header. |
| 401 | invalid_api_key | No site has this key. Keys stop working as soon as they are rotated. | Copy the current key from the dashboard, or rotate it to get a new one. |
| 403 | site_disabled | The site is disabled. | Check GET /blocks/status. See Blocks. |
| 400 | invalid_json | The body is not valid JSON. | Send a JSON body with Content-Type: application/json. |
| 400 | invalid_payload | A field is missing, has the wrong type or is too long. details says which. | Fix the fields listed in details. Check that form_id is a positive integer and every value in fields is a string. |
| 400 | no_notify_email_configured | No valid notification address in notify_emails or notify_email, and the site has no default. | Send notify_emails, or set a default notification address for the site in the dashboard. |
Notes
- Captcha. A submission is rejected only when you send a token and the provider says it is invalid (for reCAPTCHA v3, also a score below 0.5). With no token, or when the provider cannot be reached, the submission goes on to the other checks.
- IP limit. The rate limit counts submissions from that IP to any site. Blocked IPs show in GET /blocks/status and can be lifted with POST /blocks/lift.
- Reply-To. The notification’s Reply-To is the submitter’s address, found in the
email,e_mail,your-email,your_emailormailfield, or else in any value that looks like an email address. The auto-reply goes to that same address, and its Reply-To is the first notification address. - Auto-reply. Not sent for spam, or to suppressed addresses or addresses that unsubscribed from this site.
- Monthly limit. Only submissions that are not spam and within the limit count toward the account’s monthly form-submission limit. See Plans and limits.
For a walkthrough, see Forms API and Spam protection.