{"openapi":"3.1.0","info":{"title":"Formaly API","version":"1.0.0","summary":"Create, read, publish, and analyze conversational forms.","description":"The Formaly public REST API. Formaly is an AI-powered conversational form and survey platform: forms are generated from a natural-language prompt, answered through chat or a classic form view, and analyzed for themes and sentiment. Everything here is also available over the Model Context Protocol at /api/mcp.","contact":{"name":"Formaly support","email":"support@formaly.io","url":"https://www.formaly.io/contact"},"license":{"name":"Proprietary","url":"https://www.formaly.io/terms"},"termsOfService":"https://www.formaly.io/terms"},"externalDocs":{"description":"Formaly developer documentation","url":"https://www.formaly.io/docs"},"servers":[{"url":"https://www.formaly.io/api/v1","description":"Production"}],"security":[{"apiKey":[]}],"tags":[{"name":"Forms","description":"Create, read, update, and delete forms."},{"name":"Responses","description":"Read submitted responses and analytics."},{"name":"Credits","description":"Credit balance, costs, and history."}],"paths":{"/forms":{"get":{"tags":["Forms"],"operationId":"listForms","summary":"List forms","description":"Lists the authenticated account's forms, newest first. Requires the `forms:read` scope.","parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"status","in":"query","description":"Filter by publication status.","schema":{"type":"string","enum":["draft","active","closed"]}}],"responses":{"200":{"description":"A page of forms.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left in the window."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"type":"object","properties":{"forms":{"type":"array","items":{"$ref":"#/components/schemas/Form"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"401":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"tags":["Forms"],"operationId":"createForm","summary":"Create a form","description":"Creates a form from a structured script. Requires the `forms:write` scope and consumes credits. Always send an `Idempotency-Key` so a retry cannot create a duplicate.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A UUID. Repeating a request with the same key returns the original form.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateFormRequest"}}}},"responses":{"201":{"description":"The created form.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left in the window."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Form"}}}},"400":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/forms/{id}":{"parameters":[{"name":"id","in":"path","required":true,"description":"The form's ID.","schema":{"type":"string"}}],"get":{"tags":["Forms"],"operationId":"getForm","summary":"Get a form","description":"Returns one form including its `version`. Pass that value as `expected_version` on a later update to detect concurrent edits. Requires the `forms:read` scope.","responses":{"200":{"description":"The form.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left in the window."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Form"}}}},"401":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"tags":["Forms"],"operationId":"updateForm","summary":"Update a form","description":"Updates any subset of a form's fields. Requires the `forms:write` scope. Pass `expected_version` (or an `If-Match` header) for optimistic concurrency; a mismatch returns 409.","parameters":[{"name":"If-Match","in":"header","required":false,"description":"Alternative to `expected_version` in the body.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateFormRequest"}}}},"responses":{"200":{"description":"The updated form.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left in the window."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Form"}}}},"400":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["Forms"],"operationId":"deleteForm","summary":"Delete a form","description":"Permanently deletes a form and its responses. Irreversible - confirm with a human first. Requires the `forms:write` scope.","responses":{"200":{"description":"Deletion confirmation.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left in the window."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}}}}},"401":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/forms/{id}/schema":{"parameters":[{"name":"id","in":"path","required":true,"description":"The form's ID.","schema":{"type":"string"}}],"get":{"tags":["Forms"],"operationId":"getFormSchema","summary":"Get the machine-readable form schema","description":"Returns the canonical description of a form's fields, types, options, and validation rules - the shape any channel renders into its own UI. Requires the `forms:read` scope.","responses":{"200":{"description":"The form schema.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left in the window."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/forms/{id}/responses":{"parameters":[{"name":"id","in":"path","required":true,"description":"The form's ID.","schema":{"type":"string"}}],"get":{"tags":["Responses"],"operationId":"listFormResponses","summary":"List responses","description":"Lists submitted responses, including structured answers and the chat transcript where one exists. Requires the `analytics:read` scope.","parameters":[{"name":"page","in":"query","schema":{"type":"integer","minimum":1,"default":1}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"responses":{"200":{"description":"A page of responses.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left in the window."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/forms/{id}/analytics":{"parameters":[{"name":"id","in":"path","required":true,"description":"The form's ID.","schema":{"type":"string"}}],"get":{"tags":["Responses"],"operationId":"getFormAnalytics","summary":"Get form analytics","description":"Returns view and completion counts, completion rate, drop-off by question, and per-question breakdowns. Requires the `analytics:read` scope.","responses":{"200":{"description":"Analytics for the form.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left in the window."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/credits":{"get":{"tags":["Credits"],"operationId":"getCredits","summary":"Get credit balance","description":"Returns the balance, lifetime totals, the cost of every billable action, and recent transactions. Requires the `forms:read` scope.","parameters":[{"name":"history","in":"query","schema":{"type":"string","enum":["true","false"],"default":"true"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Credit balance and history.","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per window."},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests left in the window."},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix seconds when the window resets."}},"content":{"application/json":{"schema":{"type":"object","properties":{"balance":{"type":"number"},"lifetimePurchased":{"type":"number"},"lifetimeUsed":{"type":"number"},"costs":{"type":"object","additionalProperties":{"type":"number"}},"history":{"type":["array","null"],"items":{"type":"object"}}}}}}},"401":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Structured error. Branch on `error.code`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","description":"A Formaly API key, created in the dashboard under Settings -> API Keys. Format: `fml_{prefix}_{secret}`. Scopes: `forms:read`, `forms:write`, `analytics:read`."}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string","enum":["VALIDATION_ERROR","UNAUTHORIZED","INSUFFICIENT_CREDITS","FORBIDDEN","NOT_FOUND","CONFLICT","RATE_LIMITED","INTERNAL_ERROR"]},"message":{"type":"string"},"status":{"type":"integer"},"details":{"type":"object","additionalProperties":{"type":"string"}}}}}},"Pagination":{"type":"object","properties":{"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"totalPages":{"type":"integer"}}},"SurveyQuestion":{"type":"object","required":["id","type","prompt"],"properties":{"id":{"type":"string"},"type":{"type":"string","enum":["rating","multiple_choice","open","nps"]},"prompt":{"type":"string","minLength":1},"scale":{"type":"integer","description":"Upper bound for `rating` questions."},"options":{"type":"array","items":{"type":"string"}},"optional":{"type":"boolean"},"followUp":{"type":"object","properties":{"condition":{"type":"string"},"question":{"type":"string"}}}}},"SurveyScript":{"type":"object","required":["title","opening","questions","closing"],"properties":{"title":{"type":"string","minLength":1},"opening":{"type":"string"},"questions":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/SurveyQuestion"}},"closing":{"type":"string"},"collectContactInfo":{"type":"boolean"},"defaultSurveyMode":{"type":"string","enum":["chat","form"]}}},"Form":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"prompt":{"type":"string"},"status":{"type":"string","enum":["draft","active","closed"]},"script":{"$ref":"#/components/schemas/SurveyScript"},"collectContactInfo":{"type":"boolean"},"defaultSurveyMode":{"type":"string","enum":["chat","form"]},"version":{"type":"string","description":"Opaque concurrency token. Send back as `expected_version` when updating."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateFormRequest":{"type":"object","required":["title","prompt","script"],"properties":{"title":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","maxLength":2000},"prompt":{"type":"string","minLength":1,"maxLength":5000},"script":{"$ref":"#/components/schemas/SurveyScript"},"status":{"type":"string","enum":["draft","active","closed"],"default":"draft"},"collectContactInfo":{"type":"boolean","default":false},"defaultSurveyMode":{"type":"string","enum":["chat","form"],"default":"chat"},"systemPrompt":{"type":"string","maxLength":5000}}},"UpdateFormRequest":{"type":"object","description":"Any subset of a form's mutable fields.","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"description":{"type":"string","maxLength":2000},"prompt":{"type":"string","minLength":1,"maxLength":5000},"script":{"$ref":"#/components/schemas/SurveyScript"},"status":{"type":"string","enum":["draft","active","closed"]},"collectContactInfo":{"type":"boolean"},"defaultSurveyMode":{"type":"string","enum":["chat","form"]},"systemPrompt":{"type":"string","maxLength":5000},"expected_version":{"type":"string","description":"The `version` from a prior read. A mismatch returns 409 CONFLICT."}}}}}}