Source
This app’s code and revision history are public. Download a copy or explore the files below.
Public
The app’s code and revision history are public.
Run it yourself
Take the whole tree and run it on your own machine. The download needs no account. Cloning needs a sign-in.
Download .zip
bounded clone cf614aedcf4cdabfa9c45095
A copy you download is not bounded. The guarantees this app runs under - declared egress, proven invariants, writes that fail closed - live in the runtime serving this page, not in the files. What you get is auditable source you can read and run, with no runtime guarantees attached.
public/openapi.json
{
"openapi": "3.1.0",
"info": {
"title": "Forms API",
"version": "1.1.0",
"summary": "Free forms and surveys with unlimited responses, a free alternative to Typeform and Google Forms.",
"description": "Create a form in one call, send people its link, and read the responses later. No account and no API key: creating a form returns an ownerKey, which the owner routes need in the x-owner-key header (or as ?key=). The ownerKey and adminUrl read every response and change the form, so keep them private. Anyone with a form's link can read its questions and send a response; nobody can list forms. Errors are JSON with an error sentence that says what to change. Free with no limits. Full guide: https://forms-free.openapps.xyz/llms.txt",
"contact": {
"name": "OpenApps",
"url": "https://free-apps.openapps.xyz/"
}
},
"servers": [
{
"url": "https://functions.bounded.sh/apps/cf614aedcf4cdabfa9c45095/api"
}
],
"externalDocs": {
"description": "llms.txt",
"url": "https://forms-free.openapps.xyz/llms.txt"
},
"components": {
"securitySchemes": {
"ownerKey": {
"type": "apiKey",
"in": "header",
"name": "x-owner-key",
"description": "The ownerKey returned when the form was created."
}
},
"schemas": {
"QuestionType": {
"type": "string",
"enum": [
"short_text",
"long_text",
"email",
"number",
"date",
"choice",
"checkboxes",
"dropdown",
"rating",
"scale",
"yes_no"
],
"description": "rating is 1 to 5 stars; scale is 0 to 10 (the Net Promoter Score question)."
},
"Condition": {
"type": "object",
"required": [
"question",
"is"
],
"properties": {
"question": {
"type": "string",
"description": "The label or id of an earlier choice, checkboxes, dropdown or yes_no question. Stored as its id."
},
"is": {
"type": "string",
"description": "One of that question's options, or yes or no. For checkboxes, the question shows when this option is among the picks."
}
},
"description": "Show the question only when the earlier answer matches. A hidden question is skipped, even when required."
},
"QuestionInput": {
"type": "object",
"required": [
"label"
],
"properties": {
"id": {
"type": "string",
"pattern": "^[A-Za-z0-9_-]{1,32}$",
"description": "Keep an existing question's id when changing a form, so its answers stay linked."
},
"type": {
"$ref": "#/components/schemas/QuestionType",
"default": "short_text"
},
"label": {
"type": "string",
"maxLength": 300
},
"help": {
"type": "string",
"maxLength": 500
},
"required": {
"type": "boolean",
"default": false
},
"options": {
"type": "array",
"items": {
"type": "string",
"maxLength": 200
},
"maxItems": 50,
"description": "For choice and dropdown (at least two) and checkboxes (at least one)."
},
"showIf": {
"$ref": "#/components/schemas/Condition"
}
}
},
"Question": {
"type": "object",
"required": [
"id",
"type",
"label",
"required"
],
"properties": {
"id": {
"type": "string"
},
"type": {
"$ref": "#/components/schemas/QuestionType"
},
"label": {
"type": "string"
},
"help": {
"type": "string"
},
"required": {
"type": "boolean"
},
"options": {
"type": "array",
"items": {
"type": "string"
}
},
"showIf": {
"$ref": "#/components/schemas/Condition"
}
}
},
"PublicForm": {
"type": "object",
"required": [
"id",
"title",
"closed",
"questions",
"url",
"endpoint",
"howToAnswer"
],
"properties": {
"id": {
"type": "string"
},
"title": {
"type": "string"
},
"description": {
"type": "string"
},
"thankYou": {
"type": "string"
},
"closed": {
"type": "boolean"
},
"questions": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Question"
}
},
"url": {
"type": "string",
"format": "uri",
"description": "The public form. Send this to people."
},
"endpoint": {
"type": "string",
"format": "uri",
"description": "Where responses are posted."
},
"howToAnswer": {
"type": "string"
}
}
},
"Answers": {
"type": "object",
"description": "Question label (any case) or id to answer. Strings for text, email, date (2026-10-18), choice and dropdown; numbers for number, rating and scale; a list of options for checkboxes; yes or no for yes_no.",
"additionalProperties": {
"oneOf": [
{
"type": "string"
},
{
"type": "number"
},
{
"type": "array",
"items": {
"type": "string"
}
}
]
}
},
"Summary": {
"type": "object",
"required": [
"key",
"label",
"type",
"answered"
],
"properties": {
"key": {
"type": "string"
},
"label": {
"type": "string"
},
"type": {
"type": "string",
"description": "A question type, or field for a form with no questions."
},
"answered": {
"type": "integer"
},
"options": {
"type": "array",
"items": {
"type": "object",
"properties": {
"option": {
"type": "string"
},
"count": {
"type": "integer"
},
"percent": {
"type": "integer"
}
}
}
},
"average": {
"type": "number"
},
"distribution": {
"type": "array",
"items": {
"type": "integer"
},
"description": "Rating: counts for 1 to 5. Scale: counts for 0 to 10."
},
"netScore": {
"type": "integer",
"description": "Scale: percent who picked 9 or 10 minus percent who picked 0 to 6."
},
"recent": {
"type": "array",
"items": {
"type": "string"
},
"description": "Latest answers, newest first."
}
}
},
"Error": {
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "string",
"description": "A sentence that says what to change."
}
}
},
"AnswerErrors": {
"type": "object",
"required": [
"error",
"errors"
],
"properties": {
"error": {
"type": "string"
},
"errors": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "Question label to what to fix."
}
}
}
}
},
"paths": {
"/": {
"get": {
"operationId": "describe",
"summary": "Describe the API and its routes",
"responses": {
"200": {
"description": "Name, docs, question types and routes",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"about": {
"type": "string"
},
"docs": {
"type": "string"
},
"openapi": {
"type": "string"
},
"questionTypes": {
"type": "array",
"items": {
"$ref": "#/components/schemas/QuestionType"
}
},
"routes": {
"type": "array",
"items": {
"type": "string"
}
}
}
},
"example": {
"name": "Forms by OpenApps",
"docs": "https://forms-free.openapps.xyz/llms.txt",
"openapi": "https://forms-free.openapps.xyz/openapi.json",
"questionTypes": [
"short_text",
"long_text",
"email",
"number",
"date",
"choice",
"checkboxes",
"dropdown",
"rating",
"scale",
"yes_no"
]
}
}
}
}
}
}
},
"/forms": {
"post": {
"operationId": "createForm",
"summary": "Create a form",
"description": "Returns the public url to send people, and the private ownerKey and adminUrl. Leave out questions to make a website endpoint that keeps whatever fields are posted.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"title"
],
"properties": {
"title": {
"type": "string",
"maxLength": 200
},
"description": {
"type": "string",
"maxLength": 2000
},
"thankYou": {
"type": "string",
"maxLength": 1000,
"description": "Shown after someone sends the form."
},
"questions": {
"type": "array",
"maxItems": 100,
"items": {
"$ref": "#/components/schemas/QuestionInput"
}
}
}
},
"example": {
"title": "Team offsite",
"thankYou": "Thanks!",
"questions": [
{
"type": "yes_no",
"label": "Are you coming?",
"required": true
},
{
"type": "checkboxes",
"label": "Which nights?",
"options": [
"Friday",
"Saturday"
],
"required": true,
"showIf": {
"question": "Are you coming?",
"is": "yes"
}
},
{
"type": "scale",
"label": "How likely are you to recommend the offsite?"
}
]
}
}
}
},
"responses": {
"201": {
"description": "The new form",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"formId",
"url",
"endpoint",
"adminUrl",
"resultsUrl",
"ownerKey",
"form"
],
"properties": {
"formId": {
"type": "string"
},
"url": {
"type": "string",
"format": "uri"
},
"endpoint": {
"type": "string",
"format": "uri"
},
"adminUrl": {
"type": "string",
"format": "uri",
"description": "Private: the editor, with the owner key after #k=."
},
"resultsUrl": {
"type": "string",
"format": "uri",
"description": "Private: the results, with the owner key after #k=."
},
"ownerKey": {
"type": "string",
"description": "Private: for the owner routes."
},
"form": {
"$ref": "#/components/schemas/PublicForm"
},
"note": {
"type": "string"
}
}
},
"example": {
"formId": "eBuVUvp5CXD7UatMQeVz",
"url": "https://forms-free.openapps.xyz/f/eBuVUvp5CXD7UatMQeVz",
"endpoint": "https://functions.bounded.sh/apps/cf614aedcf4cdabfa9c45095/api/forms/eBuVUvp5CXD7UatMQeVz/responses",
"adminUrl": "https://forms-free.openapps.xyz/f/eBuVUvp5CXD7UatMQeVz/edit#k=OWNER_KEY",
"resultsUrl": "https://forms-free.openapps.xyz/f/eBuVUvp5CXD7UatMQeVz/results#k=OWNER_KEY",
"ownerKey": "OWNER_KEY",
"form": {
"id": "eBuVUvp5CXD7UatMQeVz",
"title": "Team offsite",
"thankYou": "Thanks!",
"closed": false,
"questions": [
{
"id": "Q1aaaaaa",
"type": "yes_no",
"label": "Are you coming?",
"required": true
},
{
"id": "Q2bbbbbb",
"type": "checkboxes",
"label": "Which nights?",
"required": true,
"options": [
"Friday",
"Saturday"
],
"showIf": {
"question": "Q1aaaaaa",
"is": "yes"
}
},
{
"id": "Q3cccccc",
"type": "scale",
"label": "How likely are you to recommend the offsite?",
"required": false
}
],
"url": "https://forms-free.openapps.xyz/f/eBuVUvp5CXD7UatMQeVz",
"endpoint": "https://functions.bounded.sh/apps/cf614aedcf4cdabfa9c45095/api/forms/eBuVUvp5CXD7UatMQeVz/responses",
"howToAnswer": "POST https://functions.bounded.sh/apps/cf614aedcf4cdabfa9c45095/api/forms/eBuVUvp5CXD7UatMQeVz/responses with {\"answers\": {\"<question id or label>\": value}}. ..."
}
}
}
}
},
"400": {
"description": "A title, question or option needs fixing",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "Question 2: showIf.question must be the id or label of an earlier question."
}
}
}
}
}
}
},
"/forms/{formId}": {
"parameters": [
{
"name": "formId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"pattern": "^[A-Za-z0-9]{8,32}$"
},
"example": "eBuVUvp5CXD7UatMQeVz"
}
],
"get": {
"operationId": "getForm",
"summary": "Read a form's questions, as the people filling it in see it",
"responses": {
"200": {
"description": "The form",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PublicForm"
},
"example": {
"id": "eBuVUvp5CXD7UatMQeVz",
"title": "Team offsite",
"thankYou": "Thanks!",
"closed": false,
"questions": [
{
"id": "Q1aaaaaa",
"type": "yes_no",
"label": "Are you coming?",
"required": true
},
{
"id": "Q2bbbbbb",
"type": "checkboxes",
"label": "Which nights?",
"required": true,
"options": [
"Friday",
"Saturday"
],
"showIf": {
"question": "Q1aaaaaa",
"is": "yes"
}
},
{
"id": "Q3cccccc",
"type": "scale",
"label": "How likely are you to recommend the offsite?",
"required": false
}
],
"url": "https://forms-free.openapps.xyz/f/eBuVUvp5CXD7UatMQeVz",
"endpoint": "https://functions.bounded.sh/apps/cf614aedcf4cdabfa9c45095/api/forms/eBuVUvp5CXD7UatMQeVz/responses",
"howToAnswer": "POST https://functions.bounded.sh/apps/cf614aedcf4cdabfa9c45095/api/forms/eBuVUvp5CXD7UatMQeVz/responses with {\"answers\": {\"<question id or label>\": value}}. ..."
}
}
}
},
"404": {
"description": "No such form",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "No form with that id."
}
}
}
}
}
},
"patch": {
"operationId": "updateForm",
"summary": "Change a form, or close and reopen it (owner)",
"security": [
{
"ownerKey": []
}
],
"parameters": [
{
"name": "x-owner-key",
"in": "header",
"required": false,
"schema": {
"type": "string"
},
"description": "The ownerKey from creating the form. Or send it as ?key=."
},
{
"name": "key",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "The ownerKey, when a header is not possible."
}
],
"description": "Send only what changes. When you send questions, include each existing question's id to keep its answers linked.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"title": {
"type": "string",
"maxLength": 200
},
"description": {
"type": "string"
},
"thankYou": {
"type": "string"
},
"closed": {
"type": "boolean",
"description": "true stops new responses; false reopens."
},
"questions": {
"type": "array",
"items": {
"$ref": "#/components/schemas/QuestionInput"
}
}
}
},
"example": {
"closed": true
}
}
}
},
"responses": {
"200": {
"description": "The form after the change",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PublicForm"
}
}
}
},
"400": {
"description": "Something needs fixing",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "closed must be true or false."
}
}
}
},
"401": {
"description": "No owner key",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "Send the form's owner key in the x-owner-key header (or as ?key=)."
}
}
}
},
"403": {
"description": "Wrong owner key",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "That owner key does not match this form."
}
}
}
},
"404": {
"description": "No such form",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "No form with that id."
}
}
}
}
}
}
},
"/forms/{formId}/responses": {
"parameters": [
{
"name": "formId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"pattern": "^[A-Za-z0-9]{8,32}$"
},
"example": "eBuVUvp5CXD7UatMQeVz"
}
],
"post": {
"operationId": "sendResponse",
"summary": "Send a response (also a website form endpoint)",
"description": "JSON {answers: {...}} returns JSON. A plain HTML form post (urlencoded or multipart, field names are question labels or ids) gets a short thank-you page unless it sends Accept: application/json. A non-empty _gotcha field is treated as a bot and nothing is stored.",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"answers"
],
"properties": {
"answers": {
"$ref": "#/components/schemas/Answers"
}
}
},
"example": {
"answers": {
"Are you coming?": "yes",
"Which nights?": [
"Saturday"
],
"How likely are you to recommend the offsite?": 9
}
}
},
"application/x-www-form-urlencoded": {
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"multipart/form-data": {
"schema": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
}
}
},
"responses": {
"201": {
"description": "Saved",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"ok",
"message"
],
"properties": {
"ok": {
"type": "boolean"
},
"responseId": {
"type": "string"
},
"message": {
"type": "string",
"description": "The form's thank-you message."
},
"ignored": {
"type": "array",
"items": {
"type": "string"
},
"description": "Fields that matched no question, or answered a question the other answers hide. Not saved."
},
"note": {
"type": "string"
}
}
},
"example": {
"ok": true,
"responseId": "kW9CYrfyjfJ77ime",
"message": "Thanks!"
}
}
}
},
"400": {
"description": "Some answers need fixing",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/AnswerErrors"
},
"example": {
"error": "Some answers need fixing.",
"errors": {
"Which nights?": "This question is required."
}
}
}
}
},
"403": {
"description": "The form is closed",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "This form is closed and no longer takes responses."
}
}
}
},
"404": {
"description": "No such form",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "No form with that id."
}
}
}
}
}
},
"get": {
"operationId": "listResponses",
"summary": "Read every response, with a summary per question (owner)",
"security": [
{
"ownerKey": []
}
],
"parameters": [
{
"name": "x-owner-key",
"in": "header",
"required": false,
"schema": {
"type": "string"
},
"description": "The ownerKey from creating the form. Or send it as ?key=."
},
{
"name": "key",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "The ownerKey, when a header is not possible."
},
{
"name": "format",
"in": "query",
"required": false,
"schema": {
"type": "string",
"enum": [
"json",
"csv"
],
"default": "json"
},
"description": "csv returns every response as CSV, oldest first."
}
],
"responses": {
"200": {
"description": "Responses, newest first",
"content": {
"application/json": {
"schema": {
"type": "object",
"required": [
"form",
"count",
"summary",
"responses"
],
"properties": {
"form": {
"$ref": "#/components/schemas/PublicForm"
},
"count": {
"type": "integer"
},
"summary": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Summary"
}
},
"responses": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"submittedAt": {
"type": "string",
"format": "date-time"
},
"answers": {
"type": "object",
"description": "Answers keyed by question label."
}
}
}
}
}
},
"example": {
"count": 1,
"summary": [
{
"key": "Q3cccccc",
"label": "How likely are you to recommend the offsite?",
"type": "scale",
"answered": 1,
"average": 9,
"distribution": [
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
0
],
"netScore": 100
}
],
"responses": [
{
"id": "kW9CYrfyjfJ77ime",
"submittedAt": "2026-10-19T18:41:52.000Z",
"answers": {
"Are you coming?": "yes",
"Which nights?": [
"Saturday"
],
"How likely are you to recommend the offsite?": 9
}
}
]
}
},
"text/csv": {
"schema": {
"type": "string"
}
}
}
},
"400": {
"description": "Unknown format",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "format must be json or csv."
}
}
}
},
"401": {
"description": "No owner key",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "Send the form's owner key in the x-owner-key header (or as ?key=)."
}
}
}
},
"403": {
"description": "Wrong owner key",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "That owner key does not match this form."
}
}
}
},
"404": {
"description": "No such form",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "No form with that id."
}
}
}
}
}
}
},
"/forms/{formId}/responses/{responseId}": {
"parameters": [
{
"name": "formId",
"in": "path",
"required": true,
"schema": {
"type": "string",
"pattern": "^[A-Za-z0-9]{8,32}$"
},
"example": "eBuVUvp5CXD7UatMQeVz"
},
{
"name": "responseId",
"in": "path",
"required": true,
"schema": {
"type": "string"
}
}
],
"delete": {
"operationId": "deleteResponse",
"summary": "Delete one response (owner)",
"security": [
{
"ownerKey": []
}
],
"parameters": [
{
"name": "x-owner-key",
"in": "header",
"required": false,
"schema": {
"type": "string"
},
"description": "The ownerKey from creating the form. Or send it as ?key=."
},
{
"name": "key",
"in": "query",
"required": false,
"schema": {
"type": "string"
},
"description": "The ownerKey, when a header is not possible."
}
],
"responses": {
"200": {
"description": "Deleted",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"ok": {
"type": "boolean"
},
"deleted": {
"type": "string"
}
}
},
"example": {
"ok": true,
"deleted": "kW9CYrfyjfJ77ime"
}
}
}
},
"401": {
"description": "No owner key",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "Send the form's owner key in the x-owner-key header (or as ?key=)."
}
}
}
},
"403": {
"description": "Wrong owner key",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "That owner key does not match this form."
}
}
}
},
"404": {
"description": "No such response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
},
"example": {
"error": "No response with that id in this form."
}
}
}
}
}
}
}
}
}
Change history
Quality pass: conditional questions, 0 to 10 scale, QR code, prefill links, results tabs, API docs
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync
Bounded source sync