{"openapi":"3.1.0","info":{"title":"SurveyTomato API","version":"1.0.0","description":"Manage surveys, campaigns, API tokens, and response data. Authenticate with `Authorization: Bearer <token>`."},"servers":[{"url":"/"}],"tags":[{"name":"Tokens","description":"API token management"},{"name":"Surveys","description":"Survey CRUD and survey code"},{"name":"Campaigns","description":"Share links for surveys"},{"name":"Responses","description":"Collected survey answers"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API token (`st_…`) or omit and use a logged-in session cookie."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]},"TokenPolicy":{"type":"string","enum":["admin","edit","contributor","read"]},"Token":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"tokenPrefix":{"type":"string"},"surveyId":{"type":"string","nullable":true},"surveyName":{"type":"string","nullable":true},"policy":{"$ref":"#/components/schemas/TokenPolicy"},"createdAt":{"type":"string","format":"date-time"}}},"CreatedToken":{"type":"object","properties":{"tokenId":{"type":"string"},"token":{"type":"string"},"name":{"type":"string"},"policy":{"$ref":"#/components/schemas/TokenPolicy"},"surveyId":{"type":"string","nullable":true}}},"Survey":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"createdAt":{"type":"string","format":"date-time","nullable":true},"surveyCode":{"type":"string","nullable":true},"engine":{"type":"string","enum":["quickjs","n8n"],"description":"Survey execution engine"},"n8nWebhookUrl":{"type":"string","format":"uri","nullable":true,"description":"n8n workflow webhook URL when engine is n8n"}}},"SurveyConfig":{"type":"object","properties":{"surveyId":{"type":"string"},"themeColor":{"type":"string","nullable":true,"description":"Brand color (#hex or oklch). Null for monochrome."},"logoUrl":{"type":"string","format":"uri","nullable":true,"description":"Custom logo shown in the survey header (http/https URL)."},"privacyPolicyUrl":{"type":"string","format":"uri","nullable":true,"description":"Privacy policy link shown in the survey footer (http/https URL)."}}},"Campaign":{"type":"object","properties":{"id":{"type":"string"},"surveyId":{"type":"string"},"name":{"type":"string"},"token":{"type":"string"},"public":{"type":"boolean"},"expires":{"type":"string","format":"date-time","nullable":true},"shareUrl":{"type":"string"}}},"Response":{"type":"object","properties":{"responseId":{"type":"string"},"startedAt":{"type":"string","format":"date-time","nullable":true},"finishedAt":{"type":"string","format":"date-time","nullable":true},"answers":{"type":"object","additionalProperties":{"type":"string"}}}}}},"security":[{"bearerAuth":[]}],"paths":{"/api/tokens":{"get":{"tags":["Tokens"],"summary":"List API tokens","responses":{"200":{"description":"Token list (secrets are prefixed only)","content":{"application/json":{"schema":{"type":"object","properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/Token"}}}}}}}}},"post":{"tags":["Tokens"],"summary":"Create an API token","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","policy"],"properties":{"name":{"type":"string"},"policy":{"$ref":"#/components/schemas/TokenPolicy"},"surveyId":{"type":"string","nullable":true,"description":"Omit or null for a user-wide token"}}}}}},"responses":{"201":{"description":"Token created; `token` is shown only once","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"$ref":"#/components/schemas/CreatedToken"}}}}}}}}},"/api/tokens/{id}":{"delete":{"tags":["Tokens"],"summary":"Delete an API token","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"},"404":{"description":"Not found"}}}},"/api/surveys":{"get":{"tags":["Surveys"],"summary":"List surveys","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":50}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Surveys in scope","content":{"application/json":{"schema":{"type":"object","properties":{"surveys":{"type":"array","items":{"$ref":"#/components/schemas/Survey"}},"limit":{"type":"integer"},"offset":{"type":"integer"}}}}}}}},"post":{"tags":["Surveys"],"summary":"Create a survey","requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"surveyCode":{"type":"string"}}}}}},"responses":{"201":{"description":"Created"}}}},"/api/surveys/{id}":{"get":{"tags":["Surveys"],"summary":"Get a survey","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Survey"},"404":{"description":"Not found"}}},"patch":{"tags":["Surveys"],"summary":"Update a survey","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"engine":{"type":"string","enum":["quickjs","n8n"]},"n8nWebhookUrl":{"type":"string","format":"uri","nullable":true}}}}}},"responses":{"200":{"description":"Updated"}}},"delete":{"tags":["Surveys"],"summary":"Delete a survey","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"}}}},"/api/surveys/{id}/code":{"get":{"tags":["Surveys"],"summary":"Get survey DSL code","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Code"}}},"put":{"tags":["Surveys"],"summary":"Replace survey DSL code","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["surveyCode"],"properties":{"surveyCode":{"type":"string"}}}}}},"responses":{"200":{"description":"Saved"}}}},"/api/surveys/{id}/config":{"get":{"tags":["Surveys"],"summary":"Get survey appearance config","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Theme color and logo URL","content":{"application/json":{"schema":{"type":"object","properties":{"config":{"$ref":"#/components/schemas/SurveyConfig"}}}}}}}},"patch":{"tags":["Surveys"],"summary":"Update survey appearance config","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"themeColor":{"type":"string","nullable":true},"logoUrl":{"type":"string","format":"uri","nullable":true},"privacyPolicyUrl":{"type":"string","format":"uri","nullable":true}}}}}},"responses":{"200":{"description":"Updated config"}}}},"/api/surveys/{id}/campaigns":{"get":{"tags":["Campaigns"],"summary":"List campaigns for a survey","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Campaigns"}}},"post":{"tags":["Campaigns"],"summary":"Create a campaign","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"public":{"type":"boolean"},"expires":{"type":"string","format":"date-time","nullable":true}}}}}},"responses":{"201":{"description":"Created"}}}},"/api/surveys/{id}/responses":{"get":{"tags":["Responses"],"summary":"List survey responses","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Responses"}}}},"/api/campaigns/{id}":{"get":{"tags":["Campaigns"],"summary":"Get a campaign","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Campaign"}}},"patch":{"tags":["Campaigns"],"summary":"Update a campaign","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"public":{"type":"boolean"},"expires":{"type":"string","format":"date-time","nullable":true}}}}}},"responses":{"200":{"description":"Updated"}}},"delete":{"tags":["Campaigns"],"summary":"Delete a campaign","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deleted"}}}}}}