{"openapi":"3.1.0","info":{"title":"Mailform API","version":"0.1.0","description":"AI-first contact form creation, installation, and inquiry management API. Email delivery is not included in this MVP."},"servers":[{"url":"https://mailform.junno.org"},{"url":"/"}],"tags":[{"name":"Public"},{"name":"Forms"},{"name":"Submissions"},{"name":"API keys"}],"paths":{"/health":{"get":{"operationId":"getHealth","responses":{"200":{"description":"Healthy"}}}},"/api/v1/forms":{"get":{"tags":["Forms"],"operationId":"listForms","security":[{"bearerAuth":[]}],"responses":{"200":{"$ref":"#/components/responses/FormList"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"}}},"post":{"tags":["Forms"],"operationId":"createForm","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormInput"}}}},"responses":{"201":{"$ref":"#/components/responses/Form"},"401":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"}}}},"/api/v1/forms/{formId}":{"parameters":[{"$ref":"#/components/parameters/FormId"}],"get":{"tags":["Forms"],"operationId":"getForm","security":[{"bearerAuth":[]}],"responses":{"200":{"$ref":"#/components/responses/Form"},"404":{"$ref":"#/components/responses/Error"}}},"patch":{"tags":["Forms"],"operationId":"updateForm","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FormPatch"}}}},"responses":{"200":{"$ref":"#/components/responses/Form"},"422":{"$ref":"#/components/responses/Error"}}},"delete":{"tags":["Forms"],"operationId":"deleteForm","security":[{"bearerAuth":[]}],"description":"Permanently deletes the form and its submissions.","responses":{"204":{"description":"Deleted"},"404":{"$ref":"#/components/responses/Error"}}}},"/api/v1/forms/{formId}/installations":{"parameters":[{"$ref":"#/components/parameters/FormId"}],"get":{"tags":["Forms"],"operationId":"getFormInstallations","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Installation methods","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstallationResponse"}}}},"404":{"$ref":"#/components/responses/Error"}}}},"/api/v1/forms/{formId}/test-submissions":{"parameters":[{"$ref":"#/components/parameters/FormId"}],"post":{"tags":["Submissions"],"operationId":"createTestSubmission","security":[{"bearerAuth":[]}],"description":"Validates against the form schema and creates an inquiry marked as test.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"201":{"$ref":"#/components/responses/Submission"},"422":{"$ref":"#/components/responses/Error"}}}},"/api/v1/public/forms/{publicKey}":{"parameters":[{"$ref":"#/components/parameters/PublicKey"}],"get":{"tags":["Public"],"operationId":"getPublicForm","security":[],"responses":{"200":{"description":"Public name, description, and schema"},"404":{"$ref":"#/components/responses/Error"}}}},"/api/v1/public/forms/{publicKey}/submissions":{"parameters":[{"$ref":"#/components/parameters/PublicKey"}],"post":{"tags":["Public"],"operationId":"createPublicSubmission","security":[],"description":"Accepts JSON or application/x-www-form-urlencoded. Fields must exactly match the public form schema.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true}},"application/x-www-form-urlencoded":{"schema":{"type":"object","additionalProperties":true}}}},"responses":{"201":{"description":"Accepted"},"303":{"description":"HTML form success redirect"},"403":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/api/v1/stats":{"get":{"operationId":"getStats","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Form and inquiry counts, filtered by the API key's formIds"}}}},"/api/v1/submissions":{"get":{"tags":["Submissions"],"operationId":"listSubmissions","security":[{"bearerAuth":[]}],"parameters":[{"name":"formId","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"$ref":"#/components/schemas/SubmissionStatus"}},{"name":"search","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"responses":{"200":{"$ref":"#/components/responses/SubmissionList"},"400":{"$ref":"#/components/responses/Error"}}}},"/api/v1/submissions/{submissionId}":{"parameters":[{"$ref":"#/components/parameters/SubmissionId"}],"get":{"tags":["Submissions"],"operationId":"getSubmission","security":[{"bearerAuth":[]}],"responses":{"200":{"$ref":"#/components/responses/Submission"},"404":{"$ref":"#/components/responses/Error"}}},"patch":{"tags":["Submissions"],"operationId":"updateSubmissionStatus","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["status"],"properties":{"status":{"$ref":"#/components/schemas/SubmissionStatus"}},"additionalProperties":false}}}},"responses":{"200":{"$ref":"#/components/responses/Submission"},"422":{"$ref":"#/components/responses/Error"}}},"delete":{"tags":["Submissions"],"operationId":"deleteSubmission","security":[{"bearerAuth":[]}],"responses":{"204":{"description":"Deleted"},"404":{"$ref":"#/components/responses/Error"}}}},"/api/v1/submissions/{submissionId}/notes":{"parameters":[{"$ref":"#/components/parameters/SubmissionId"}],"post":{"tags":["Submissions"],"operationId":"createSubmissionNote","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["body"],"properties":{"body":{"type":"string","maxLength":2000}},"additionalProperties":false}}}},"responses":{"201":{"description":"Created note"},"422":{"$ref":"#/components/responses/Error"}}}},"/api/v1/api-keys":{"get":{"tags":["API keys"],"operationId":"listApiKeys","security":[{"bearerAuth":[]}],"description":"Bootstrap administrator only.","responses":{"200":{"description":"Keys without token values"},"403":{"$ref":"#/components/responses/Error"}}},"post":{"tags":["API keys"],"operationId":"createApiKey","security":[{"bearerAuth":[]}],"description":"Bootstrap administrator only. The token is returned exactly once.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyInput"}}}},"responses":{"201":{"description":"Created key and one-time token"},"403":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"}}}},"/api/v1/api-keys/{keyId}":{"delete":{"tags":["API keys"],"operationId":"revokeApiKey","security":[{"bearerAuth":[]}],"parameters":[{"name":"keyId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Revoked"},"404":{"$ref":"#/components/responses/Error"}}}},"/api/v1/audit-logs":{"get":{"operationId":"listAuditLogs","security":[{"bearerAuth":[]}],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":100}}],"responses":{"200":{"description":"Audit events without inquiry content"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"Mailform API key"}},"parameters":{"FormId":{"name":"formId","in":"path","required":true,"schema":{"type":"string"}},"PublicKey":{"name":"publicKey","in":"path","required":true,"schema":{"type":"string","pattern":"^pub_"}},"SubmissionId":{"name":"submissionId","in":"path","required":true,"schema":{"type":"string"}}},"schemas":{"Field":{"type":"object","required":["name","label","type","required"],"properties":{"name":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,63}$"},"label":{"type":"string","maxLength":100},"type":{"enum":["text","email","tel","textarea","url","select","checkbox"]},"required":{"type":"boolean"},"maxLength":{"type":"integer","minimum":1,"maximum":5000},"options":{"type":"array","minItems":1,"maxItems":50,"items":{"type":"string"}}},"additionalProperties":false},"FormInput":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":100},"description":{"type":"string","maxLength":500},"status":{"enum":["active","paused"],"default":"active"},"schema":{"type":"array","minItems":1,"maxItems":30,"items":{"$ref":"#/components/schemas/Field"}},"allowedOrigins":{"type":"array","maxItems":20,"items":{"type":"string","format":"uri"}}},"additionalProperties":false},"FormPatch":{"type":"object","properties":{"name":{"type":"string","maxLength":100},"description":{"type":"string","maxLength":500},"status":{"enum":["active","paused"]},"schema":{"type":"array","minItems":1,"maxItems":30,"items":{"$ref":"#/components/schemas/Field"}},"allowedOrigins":{"type":"array","maxItems":20,"items":{"type":"string","format":"uri"}}},"additionalProperties":false},"Form":{"type":"object","required":["id","publicKey","name","status","schema","allowedOrigins","createdAt","updatedAt"],"properties":{"id":{"type":"string"},"publicKey":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"status":{"enum":["active","paused"]},"schema":{"type":"array","items":{"$ref":"#/components/schemas/Field"}},"allowedOrigins":{"type":"array","items":{"type":"string","format":"uri"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"SubmissionStatus":{"enum":["unread","in_progress","resolved","spam"]},"Submission":{"type":"object","required":["id","formId","status","data","createdAt"],"properties":{"id":{"type":"string"},"formId":{"type":"string"},"formName":{"type":"string"},"status":{"$ref":"#/components/schemas/SubmissionStatus"},"data":{"type":"object","additionalProperties":true},"metadata":{"type":"object","additionalProperties":true},"isTest":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"ApiKeyInput":{"type":"object","required":["name"],"properties":{"name":{"type":"string","maxLength":100},"scopes":{"type":"array","minItems":1,"items":{"enum":["forms:read","forms:write","submissions:read","submissions:write","audit:read"]}},"formIds":{"type":["array","null"],"items":{"type":"string"}}},"additionalProperties":false},"InstallationResponse":{"type":"object","properties":{"data":{"type":"object","properties":{"formId":{"type":"string"},"publicKey":{"type":"string"},"action":{"type":"string","format":"uri"},"hostedUrl":{"type":"string","format":"uri"},"html":{"type":"string"},"jsonExample":{"type":"object"}}}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","requestId"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{},"requestId":{"type":"string"}}}}}},"responses":{"Form":{"description":"Form","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Form"}}}}}},"FormList":{"description":"Forms","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Form"}}}}}}},"Submission":{"description":"Submission","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Submission"}}}}}},"SubmissionList":{"description":"Cursor-paginated submissions","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Submission"}},"pagination":{"type":"object","properties":{"nextCursor":{"type":["string","null"]}}}}}}}},"Error":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}