Formulir API Reference
Formulir's public REST API — fetch a form definition and submit a response. Project-scoped publishable key required.
TODO: translate to Indonesian. English source is authoritative; render it into Indonesian below.
The Formulir public API has exactly two endpoints: fetch a form definition, and submit a response. Reading submissions is a dashboard feature and is not part of the public API.
For day-to-day embedding you usually do not call this API directly — use the iframe, React component, or script tag. This reference is for posting submissions yourself.
Base URL
https://api.sawala.cloud/public/formulirThe embed delivery host (iframe, formulir.js, formulir.css) is https://formulir.id — see how to embed a form.
Authentication
Send a project-scoped publishable key (pk_live_…) in the X-API-Key header. The key must be scoped to a single organization and project; an org-only key is rejected.
X-API-Key: pk_live_…A request whose key carries no project scope returns 400 with { "error": "API_KEY_REQUIRES_PROJECT_SCOPE" }. A bad or revoked key returns 401. See API keys and access and CLI and SDK.
Endpoints
Get a form definition
GET /forms/{slug}Returns the form's fields and settings. Use this to render the form yourself.
Submit a response
POST /forms/{slug}/submitOn success returns 201 with:
{ "id": "…", "status": "received" }id is a UUID identifying the stored submission.
Submit body
Send the field values as JSON. The canonical form wraps them in a data object:
{
"data": {
"name": "Ada Lovelace",
"email": "ada@example.com",
"message": "Hello!"
}
}A flat { "field": value } object (no data wrapper) is also accepted. Keys match each field's name.
curl -X POST https://api.sawala.cloud/public/formulir/forms/contact/submit \
-H "X-API-Key: pk_live_…" \
-H "Content-Type: application/json" \
-d '{ "data": { "name": "Ada", "email": "ada@example.com", "message": "Hello!" } }'File upload fields
For media fields, submit the request as multipart/form-data in a single request — include the file alongside the other fields. Formulir stores the file for you; there is no separate upload step or assetId to manage.
curl -X POST https://api.sawala.cloud/public/formulir/forms/contact/submit \
-H "X-API-Key: pk_live_…" \
-F "name=Ada" \
-F "resume=@./resume.pdf"Spam protection
If a form has Cloudflare Turnstile enabled, include the challenge token in the submission under the key cf-turnstile-response. See spam protection for setup.
Error codes
Errors are returned as a flat { "error": "CODE" } body.
| HTTP | error | Cause |
|---|---|---|
400 | API_KEY_REQUIRES_PROJECT_SCOPE | Key is not scoped to a project |
400 | INVALID_JSON | Request body is not valid JSON |
400 | CAPTCHA_REQUIRED | Form requires Turnstile but no token was sent |
401 | — | Missing, invalid, or revoked API key |
403 | FORM_PRIVATE | Form visibility is set to private |
403 | CAPTCHA_FAILED | Turnstile token was rejected |
404 | FORM_NOT_FOUND | No published form matches the slug |
413 | — | Payload too large |
429 | RATE_LIMITED | Submission rate limit exceeded |
503 | CAPTCHA_NOT_CONFIGURED | Form has Turnstile enabled but the project has no Turnstile keys saved |
Rate limit
Submissions are limited to 60 per minute, per API key, per form. Over the limit, the gateway returns 429 with { "error": "RATE_LIMITED" }.
Stored metadata
Each submission is stored with its timestamp, the submitter's IP address, and user agent. Submissions and any uploaded files are viewable in the dashboard inbox.
How to embed a form
Three ways to embed a Formulir form on your site — hosted iframe, the React component, or a script tag. When to pick which, with the correct embed URLs.
What is Kodena
Kodena is Sawala Cloud's hosting & deployment product — ship a static site or a small Worker to the edge, with custom domains and one-command deploys.