Server-side submits
Send Submissions from your own server with a Submit Key.
When your server sends the Submission instead of the visitor's browser (a Next.js server action, a PHP handler, a queue worker), send a Submit Key with it. A Submit Key belongs to one Project and can only create Submissions.
Get a Submit Key
Submit Keys will be created from the Project's API keys screen in the
dashboard, which is coming soon. Keys start with if_. Keep yours on the
server, in an environment variable, and never ship it to the browser.
Send it
Put the key in the Authorization header as a Bearer token. Add the visitor's
IP address in X-Visitor-IP:
A Next.js server action:
The same request with curl:
A successful request answers 201 {"ok": true, "id": "..."}, the same as a
browser submit. The other errors in the
JavaScript fetch table apply too.
What a Submit Key changes
With a valid Submit Key:
- The origin check is skipped. A server has no browser origin, so the Form's Allowed Origins don't apply.
X-Visitor-IPis used. The rate limits count the visitor's address instead of your server's.- Direct upload requests to
/f/YOUR_FORM_ID/uploadsaccept the key too.
Turnstile still applies. If the Form uses it, forward the visitor's
cf-turnstile-response field in the body.
Gotchas
- Without
X-Visitor-IP, the limits count your server's address. A server relaying every visitor then shares the limit of 10 requests a minute, so pass the visitor's address whenever you have it. The header has to hold a valid IPv4 or IPv6 address, or it's ignored. The IP is never stored. - A request without a Submit Key counts as a browser submit: its
X-Visitor-IPis ignored and Allowed Origins apply. - A key that is unknown, switched off, expired, belongs to another Project or
isn't a Submit Key gets
403 invalid_submit_key. So does a malformedAuthorizationheader, such asBasic …or a Bearer header with no token. - A revoked key can keep working for up to a minute, because key lookups are cached for 60 seconds. Unknown keys are cached the same way.
- Browsers can't send these headers to the endpoint: its CORS answer allows
only
Content-Type. Send from a server.