FormalyFormaly
FeaturesWhyComparePricingBlog
Developers

Formaly Developer Documentation

Formaly is API-first and agent-native. Every form can be created, read, published, answered, and analyzed by software - over a REST API, over the Model Context Protocol, from a JavaScript SDK, or inside an iframe embed. This is the index of Formaly's developer resources.

› Developers

Formaly developer resources

ResourceURLWhat it is
Formaly REST API reference/docs/apiEvery /api/v1 endpoint, with parameters and error codes
Formaly OpenAPI spec/openapi.jsonOpenAPI 3.1 description of the public REST API
Formaly MCP server/docs/mcpModel Context Protocol endpoint and tool catalogue
Formaly agent guide/AGENTS.mdWhen and how an autonomous agent should call Formaly
Formaly llms.txt/llms.txtMachine-readable site summary and endpoint index
Formaly JavaScript SDKformaly-sdk on npmIn-product surveys, also served at /formaly-sdk.js
Formaly embed script/embed.jsDrop-in iframe embed for any website

Authentication

The public API and the MCP server share one credential: a Formaly API key. Create keys in the dashboard under Settings → API Keys. A key looks like fml_<prefix>_<secret>; only a SHA-256 hash is stored, so the secret is shown once at creation and cannot be recovered afterwards.

Send the key as a bearer token on every request. Session cookies authenticate the dashboard only - they are not accepted on /api/v1.

curl https://www.formaly.io/api/v1/forms \
  -H "Authorization: Bearer fml_abc123_your_secret_here"

Scopes

Each key carries an explicit set of scopes. A request without the required scope fails with FORBIDDEN (403), which is not retryable - it needs a different key, not a second attempt.

ScopeGrants
forms:readList and read forms, read the form schema, read credit balance
forms:writeCreate, update, publish, and delete forms
analytics:readRead responses and analytics

Rate limits

Every API response carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset. When a limit is exceeded the request fails with RATE_LIMITED (429) and a Retry-After header - back off for that many seconds rather than retrying immediately.

Errors

Every failure from the Formaly API is a JSON object with a stable machine-readable code. Branch on code; show message to a human; read details for per-field validation errors.

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Request body is invalid. See details for specific fields.",
    "status": 400,
    "details": { "script.questions": "Script must include at least one question." }
  }
}
CodeStatusMeaning
VALIDATION_ERROR400The request body or query is malformed. Fix and retry.
UNAUTHORIZED401Missing, malformed, or revoked API key.
INSUFFICIENT_CREDITS402The account is out of credits. The user must top up.
FORBIDDEN403The key lacks the required scope. Not retryable.
NOT_FOUND404No such form, or it belongs to another account.
CONFLICT409expected_version did not match. Re-read and retry.
RATE_LIMITED429Too many requests. Honour Retry-After.
INTERNAL_ERROR500Something broke on our side. Retry with backoff.

Safe writes

Two mechanisms make write operations safe to retry, which matters most when the caller is an autonomous agent.

  • Idempotency. POST /api/v1/forms accepts an Idempotency-Key header. Send a UUID with every create; a retry with the same key returns the original form instead of making a duplicate.
  • Optimistic concurrency. PATCH /api/v1/forms/{id} accepts expected_version (from a prior read) in the body, or the same value as an If-Match header. A mismatch fails with CONFLICT (409) rather than silently overwriting someone else's edit.

Embedding and in-product surveys

Any published form has an embeddable URL at /embed/{id} which sets frame-ancestors *, so it can be iframed from any origin. For a drop-in script, /embed.js renders the iframe and handles sizing.

For surveys shown inside your own product - triggered on an event, targeted at a user segment - use the formaly-sdk npm package, or load the CDN bundle from /formaly-sdk.js.

<script src="https://www.formaly.io/embed.js" data-formaly-id="YOUR_FORM_ID" async></script>

Webhooks

Formaly can POST to your endpoint when a response is submitted or a form is closed. Configure webhook endpoints per form in the dashboard. Deliveries are signed and retried with exponential backoff; the delivery log in the dashboard shows every attempt and lets you replay one.

FormalyFormaly

Talk to build. Talk to answer.

© 2026 Formaly

AboutDocsBlogComparePrivacyTermsContact

Made by Arindam

Formaly