{"openapi": "3.1.0", "jsonSchemaDialect": "https://spec.openapis.org/oas/3.1/dialect/base", "info": {"title": "Open Foris Support API", "version": "1.0", "summary": "Read the questions, answers, tags and members of the forum, and post with a personal access token.", "description": "Lists are {\"data\": [...], \"next\": url or null} with the same URL in a Link header (rel=\"next\"); single objects are returned as they are. Dates are ISO 8601 with the site's UTC offset. Errors are RFC 9457 problem details (application/problem+json); their types are explained at https://openforis.support/api/#problems."}, "servers": [{"url": "https://openforis.support"}], "tags": [{"name": "About", "description": "The index and this document."}, {"name": "Questions", "description": "Lists, search, one question with its answers and comments; asking and following."}, {"name": "Answers", "description": "Answers of a question, one answer; answering and accepting."}, {"name": "Comments", "description": "Commenting on questions and answers."}, {"name": "Votes", "description": "Voting on questions and answers."}, {"name": "Tags", "description": "Tags and their synonyms."}, {"name": "Members", "description": "Public profiles, badges and the token owner."}], "paths": {"/api/v1/": {"get": {"operationId": "index", "summary": "API index", "description": "Links to the documentation, the OpenAPI document and the lists. No token.", "tags": ["About"], "security": [], "responses": {"200": {"description": "OK.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Index"}}}}}}}, "/api/v1/openapi.json": {"get": {"operationId": "openapi", "summary": "OpenAPI document", "description": "This API described as OpenAPI 3.1, generated from the code. No token.", "tags": ["About"], "security": [], "responses": {"200": {"description": "OK.", "content": {"application/json": {"schema": {"type": "object", "description": "The OpenAPI 3.1 document."}}}}}}}, "/api/v1/me": {"get": {"operationId": "me", "summary": "The token's owner", "description": "Who the token belongs to, its scopes and expiry. Needs a token.", "tags": ["Members"], "security": [{"bearerAuth": ["read"]}], "responses": {"200": {"description": "OK.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Me"}}}, "headers": {"X-RateLimit-Limit": {"description": "Requests allowed per minute.", "schema": {"type": "integer"}}, "X-RateLimit-Remaining": {"description": "Requests left in this minute.", "schema": {"type": "integer"}}, "X-RateLimit-Reset": {"description": "Seconds until the minute resets.", "schema": {"type": "integer"}}, "ETag": {"description": "Send it back in If-None-Match to get 304 when nothing changed.", "schema": {"type": "string"}}}}, "304": {"description": "Not modified (If-None-Match matched the ETag)."}, "401": {"description": "Authentication required, Invalid token", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "403": {"description": "Account suspended", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}}}}, "/api/v1/questions": {"get": {"operationId": "listQuestions", "summary": "List questions", "description": "Questions the viewer may see, newest activity first by default. Held posts are listed for their author and moderators only, as on the site. Token optional (with one you also see your own posts waiting for review).", "tags": ["Questions"], "security": [{}, {"bearerAuth": ["read"]}], "parameters": [{"name": "tags", "in": "query", "required": false, "description": "Only questions with every one of these tags (names separated by spaces or commas; synonyms work).", "schema": {"type": "string"}, "example": "collect export"}, {"name": "status", "in": "query", "required": false, "description": "unanswered, answered or accepted (has an accepted answer).", "schema": {"enum": ["unanswered", "answered", "accepted"]}}, {"name": "sort", "in": "query", "required": false, "description": "active (latest activity), newest (asked) or votes (score).", "schema": {"enum": ["active", "newest", "votes"], "default": "active"}}, {"name": "since", "in": "query", "required": false, "description": "Only questions with activity (asked, answered, commented, edited) at or after this date or time (ISO 8601).", "schema": {"type": "string", "format": "date-time"}, "example": "2026-01-31"}, {"name": "limit", "in": "query", "required": false, "description": "Items per page.", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 30}}, {"name": "cursor", "in": "query", "required": false, "description": "Where the page starts: take it from the next link of the previous page.", "schema": {"type": "string"}}], "responses": {"200": {"description": "OK.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/QuestionPage"}}}, "headers": {"X-RateLimit-Limit": {"description": "Requests allowed per minute.", "schema": {"type": "integer"}}, "X-RateLimit-Remaining": {"description": "Requests left in this minute.", "schema": {"type": "integer"}}, "X-RateLimit-Reset": {"description": "Seconds until the minute resets.", "schema": {"type": "integer"}}, "Link": {"description": "rel=\"next\": the next page, as in the body's next.", "schema": {"type": "string"}}}}, "400": {"description": "Bad request", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "401": {"description": "Invalid token", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "429": {"description": "Too many requests", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}}}, "post": {"operationId": "askQuestion", "summary": "Ask a question", "description": "As the ask page: the same length and tag rules, hourly limit and review of first posts (held_for_review is true while a held post waits for a moderator). Needs a token with the write scope.", "tags": ["Questions"], "security": [{"bearerAuth": ["write"]}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/NewQuestion"}, "example": {"title": "How do I export survey data to CSV?", "text": "I need the data in **R**. Which menu exports it?", "tags": ["collect", "export"]}}}}, "responses": {"201": {"description": "Created.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Question"}}}, "headers": {"X-RateLimit-Limit": {"description": "Requests allowed per minute.", "schema": {"type": "integer"}}, "X-RateLimit-Remaining": {"description": "Requests left in this minute.", "schema": {"type": "integer"}}, "X-RateLimit-Reset": {"description": "Seconds until the minute resets.", "schema": {"type": "integer"}}, "Location": {"description": "URL of the new object.", "schema": {"type": "string"}}}}, "401": {"description": "Authentication required, Invalid token", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "403": {"description": "Insufficient scope, Account suspended, Writing through the API is turned off, Not allowed, Email confirmation required, Use the web site", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "429": {"description": "Too many requests, Posting limit reached", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "422": {"description": "Invalid data, Looks like spam", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}}}}, "/api/v1/questions/{id}": {"get": {"operationId": "getQuestion", "summary": "A question with its answers and comments", "description": "Rendered HTML and Markdown source of every post. Supports If-None-Match (ETag, 304). Token optional (with one you also see your own posts waiting for review).", "tags": ["Questions"], "security": [{}, {"bearerAuth": ["read"]}], "parameters": [{"name": "id", "in": "path", "required": true, "description": "The question id.", "schema": {"type": "integer"}, "example": 1}], "responses": {"200": {"description": "OK.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Question"}}}, "headers": {"X-RateLimit-Limit": {"description": "Requests allowed per minute.", "schema": {"type": "integer"}}, "X-RateLimit-Remaining": {"description": "Requests left in this minute.", "schema": {"type": "integer"}}, "X-RateLimit-Reset": {"description": "Seconds until the minute resets.", "schema": {"type": "integer"}}, "ETag": {"description": "Send it back in If-None-Match to get 304 when nothing changed.", "schema": {"type": "string"}}}}, "304": {"description": "Not modified (If-None-Match matched the ETag)."}, "404": {"description": "Not found", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "401": {"description": "Invalid token", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "429": {"description": "Too many requests", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}}}}, "/api/v1/questions/{id}/answers": {"get": {"operationId": "listAnswers", "summary": "A question's answers", "description": "Accepted first, then by score, each with its comments (all of them: next is always null). Token optional (with one you also see your own posts waiting for review).", "tags": ["Answers"], "security": [{}, {"bearerAuth": ["read"]}], "parameters": [{"name": "id", "in": "path", "required": true, "description": "The question id.", "schema": {"type": "integer"}, "example": 1}], "responses": {"200": {"description": "OK.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/AnswerList"}}}, "headers": {"X-RateLimit-Limit": {"description": "Requests allowed per minute.", "schema": {"type": "integer"}}, "X-RateLimit-Remaining": {"description": "Requests left in this minute.", "schema": {"type": "integer"}}, "X-RateLimit-Reset": {"description": "Seconds until the minute resets.", "schema": {"type": "integer"}}}}, "404": {"description": "Not found", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "401": {"description": "Invalid token", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "429": {"description": "Too many requests", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}}}, "post": {"operationId": "postAnswer", "summary": "Answer a question", "description": "Closed and deleted questions take no answers. Needs a token with the write scope.", "tags": ["Answers"], "security": [{"bearerAuth": ["write"]}], "parameters": [{"name": "id", "in": "path", "required": true, "description": "The question id.", "schema": {"type": "integer"}, "example": 1}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/NewAnswer"}, "example": {"text": "Use **File > Export > CSV** in the designer."}}}}, "responses": {"201": {"description": "Created.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Answer"}}}, "headers": {"X-RateLimit-Limit": {"description": "Requests allowed per minute.", "schema": {"type": "integer"}}, "X-RateLimit-Remaining": {"description": "Requests left in this minute.", "schema": {"type": "integer"}}, "X-RateLimit-Reset": {"description": "Seconds until the minute resets.", "schema": {"type": "integer"}}, "Location": {"description": "URL of the new object.", "schema": {"type": "string"}}}}, "401": {"description": "Authentication required, Invalid token", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "403": {"description": "Insufficient scope, Account suspended, Writing through the API is turned off, Not allowed, Email confirmation required, Use the web site", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "429": {"description": "Too many requests, Posting limit reached", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "404": {"description": "Not found", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "409": {"description": "Conflict", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "422": {"description": "Invalid data, Looks like spam", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}}}}, "/api/v1/answers/{id}": {"get": {"operationId": "getAnswer", "summary": "An answer with its comments", "description": "Supports If-None-Match (ETag, 304). Token optional (with one you also see your own posts waiting for review).", "tags": ["Answers"], "security": [{}, {"bearerAuth": ["read"]}], "parameters": [{"name": "id", "in": "path", "required": true, "description": "The answer id.", "schema": {"type": "integer"}, "example": 1}], "responses": {"200": {"description": "OK.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Answer"}}}, "headers": {"X-RateLimit-Limit": {"description": "Requests allowed per minute.", "schema": {"type": "integer"}}, "X-RateLimit-Remaining": {"description": "Requests left in this minute.", "schema": {"type": "integer"}}, "X-RateLimit-Reset": {"description": "Seconds until the minute resets.", "schema": {"type": "integer"}}, "ETag": {"description": "Send it back in If-None-Match to get 304 when nothing changed.", "schema": {"type": "string"}}}}, "304": {"description": "Not modified (If-None-Match matched the ETag)."}, "404": {"description": "Not found", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "401": {"description": "Invalid token", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "429": {"description": "Too many requests", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}}}}, "/api/v1/search": {"get": {"operationId": "search", "summary": "Search questions", "description": "The site search (full text, best matches first) with the filters of the search page. Returns at most limit results (next is always null). Only published questions are found. Token optional (with one you also see your own posts waiting for review).", "tags": ["Questions"], "security": [{}, {"bearerAuth": ["read"]}], "parameters": [{"name": "q", "in": "query", "required": true, "description": "What to look for. The search operators work: \"a phrase\", -word, [tag], user:name, is:answered.", "schema": {"type": "string"}, "example": "export csv"}, {"name": "tags", "in": "query", "required": false, "description": "Every one of these tags.", "schema": {"type": "string"}}, {"name": "status", "in": "query", "required": false, "description": "unanswered, answered or accepted.", "schema": {"enum": ["unanswered", "answered", "accepted"]}}, {"name": "closed", "in": "query", "required": false, "description": "hide leaves out closed questions.", "schema": {"enum": ["hide"]}}, {"name": "date", "in": "query", "required": false, "description": "Asked in the last week, month or year.", "schema": {"enum": ["week", "month", "year"]}}, {"name": "from", "in": "query", "required": false, "description": "Asked on or after (YYYY-MM-DD).", "schema": {"type": "string", "format": "date"}}, {"name": "to", "in": "query", "required": false, "description": "Asked on or before (YYYY-MM-DD).", "schema": {"type": "string", "format": "date"}}, {"name": "author", "in": "query", "required": false, "description": "Asked by this member (username).", "schema": {"type": "string"}}, {"name": "code", "in": "query", "required": false, "description": "The question or an answer has a code block.", "schema": {"enum": ["1"]}}, {"name": "min_score", "in": "query", "required": false, "description": "A score of at least this.", "schema": {"type": "integer"}}, {"name": "version", "in": "query", "required": false, "description": "The question or one of its answers applies to this version (of the given tags, if any).", "schema": {"type": "string", "maxLength": 20}}, {"name": "limit", "in": "query", "required": false, "description": "How many results.", "schema": {"type": "integer", "minimum": 1, "maximum": 50, "default": 20}}], "responses": {"200": {"description": "OK.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/QuestionPage"}}}, "headers": {"X-RateLimit-Limit": {"description": "Requests allowed per minute.", "schema": {"type": "integer"}}, "X-RateLimit-Remaining": {"description": "Requests left in this minute.", "schema": {"type": "integer"}}, "X-RateLimit-Reset": {"description": "Seconds until the minute resets.", "schema": {"type": "integer"}}}}, "400": {"description": "Bad request", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "401": {"description": "Invalid token", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "429": {"description": "Too many requests", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}}}}, "/api/v1/tags": {"get": {"operationId": "listTags", "summary": "List tags", "description": "Tags in use, with their synonyms. Token optional (with one you also see your own posts waiting for review).", "tags": ["Tags"], "security": [{}, {"bearerAuth": ["read"]}], "parameters": [{"name": "q", "in": "query", "required": false, "description": "Only tags whose name contains this.", "schema": {"type": "string"}}, {"name": "sort", "in": "query", "required": false, "description": "popular or name.", "schema": {"enum": ["popular", "name"], "default": "popular"}}, {"name": "limit", "in": "query", "required": false, "description": "Items per page.", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 30}}, {"name": "cursor", "in": "query", "required": false, "description": "Where the page starts: take it from the next link of the previous page.", "schema": {"type": "string"}}], "responses": {"200": {"description": "OK.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TagPage"}}}, "headers": {"X-RateLimit-Limit": {"description": "Requests allowed per minute.", "schema": {"type": "integer"}}, "X-RateLimit-Remaining": {"description": "Requests left in this minute.", "schema": {"type": "integer"}}, "X-RateLimit-Reset": {"description": "Seconds until the minute resets.", "schema": {"type": "integer"}}, "Link": {"description": "rel=\"next\": the next page, as in the body's next.", "schema": {"type": "string"}}}}, "400": {"description": "Bad request", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "401": {"description": "Invalid token", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "429": {"description": "Too many requests", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}}}}, "/api/v1/tags/{name}": {"get": {"operationId": "getTag", "summary": "A tag", "description": "A synonym gives the tag it stands for. Token optional (with one you also see your own posts waiting for review).", "tags": ["Tags"], "security": [{}, {"bearerAuth": ["read"]}], "parameters": [{"name": "name", "in": "path", "required": true, "description": "The tag name (or one of its synonyms).", "schema": {"type": "string"}, "example": "collect"}], "responses": {"200": {"description": "OK.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Tag"}}}, "headers": {"X-RateLimit-Limit": {"description": "Requests allowed per minute.", "schema": {"type": "integer"}}, "X-RateLimit-Remaining": {"description": "Requests left in this minute.", "schema": {"type": "integer"}}, "X-RateLimit-Reset": {"description": "Seconds until the minute resets.", "schema": {"type": "integer"}}, "ETag": {"description": "Send it back in If-None-Match to get 304 when nothing changed.", "schema": {"type": "string"}}}}, "304": {"description": "Not modified (If-None-Match matched the ETag)."}, "404": {"description": "Not found", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "401": {"description": "Invalid token", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "429": {"description": "Too many requests", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}}}}, "/api/v1/users": {"get": {"operationId": "listUsers", "summary": "List members", "description": "Public profile fields only. Token optional (with one you also see your own posts waiting for review).", "tags": ["Members"], "security": [{}, {"bearerAuth": ["read"]}], "parameters": [{"name": "q", "in": "query", "required": false, "description": "Only members whose username contains this.", "schema": {"type": "string"}}, {"name": "sort", "in": "query", "required": false, "description": "reputation, newest or name.", "schema": {"enum": ["reputation", "newest", "name"], "default": "reputation"}}, {"name": "limit", "in": "query", "required": false, "description": "Items per page.", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 30}}, {"name": "cursor", "in": "query", "required": false, "description": "Where the page starts: take it from the next link of the previous page.", "schema": {"type": "string"}}], "responses": {"200": {"description": "OK.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UserPage"}}}, "headers": {"X-RateLimit-Limit": {"description": "Requests allowed per minute.", "schema": {"type": "integer"}}, "X-RateLimit-Remaining": {"description": "Requests left in this minute.", "schema": {"type": "integer"}}, "X-RateLimit-Reset": {"description": "Seconds until the minute resets.", "schema": {"type": "integer"}}, "Link": {"description": "rel=\"next\": the next page, as in the body's next.", "schema": {"type": "string"}}}}, "400": {"description": "Bad request", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "401": {"description": "Invalid token", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "429": {"description": "Too many requests", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}}}}, "/api/v1/users/{id}": {"get": {"operationId": "getUser", "summary": "A member's public profile", "description": "Token optional (with one you also see your own posts waiting for review).", "tags": ["Members"], "security": [{}, {"bearerAuth": ["read"]}], "parameters": [{"name": "id", "in": "path", "required": true, "description": "The member id.", "schema": {"type": "integer"}, "example": 1}], "responses": {"200": {"description": "OK.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/User"}}}, "headers": {"X-RateLimit-Limit": {"description": "Requests allowed per minute.", "schema": {"type": "integer"}}, "X-RateLimit-Remaining": {"description": "Requests left in this minute.", "schema": {"type": "integer"}}, "X-RateLimit-Reset": {"description": "Seconds until the minute resets.", "schema": {"type": "integer"}}, "ETag": {"description": "Send it back in If-None-Match to get 304 when nothing changed.", "schema": {"type": "string"}}}}, "304": {"description": "Not modified (If-None-Match matched the ETag)."}, "404": {"description": "Not found", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "401": {"description": "Invalid token", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "429": {"description": "Too many requests", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}}}}, "/api/v1/badges": {"get": {"operationId": "listBadges", "summary": "List badges", "description": "Every badge, gold first (next is always null). Token optional (with one you also see your own posts waiting for review).", "tags": ["Members"], "security": [{}, {"bearerAuth": ["read"]}], "responses": {"200": {"description": "OK.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/BadgeList"}}}, "headers": {"X-RateLimit-Limit": {"description": "Requests allowed per minute.", "schema": {"type": "integer"}}, "X-RateLimit-Remaining": {"description": "Requests left in this minute.", "schema": {"type": "integer"}}, "X-RateLimit-Reset": {"description": "Seconds until the minute resets.", "schema": {"type": "integer"}}}}, "400": {"description": "Bad request", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "401": {"description": "Invalid token", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "429": {"description": "Too many requests", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}}}}, "/api/v1/posts/{id}/comments": {"post": {"operationId": "postComment", "summary": "Comment on a question or an answer", "description": "Needs the reputation to comment (except on your own posts and answers to your question). Needs a token with the write scope.", "tags": ["Comments"], "security": [{"bearerAuth": ["write"]}], "parameters": [{"name": "id", "in": "path", "required": true, "description": "The question or answer id.", "schema": {"type": "integer"}, "example": 1}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/NewComment"}, "example": {"text": "Which version do you use?"}}}}, "responses": {"201": {"description": "Created.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Comment"}}}, "headers": {"X-RateLimit-Limit": {"description": "Requests allowed per minute.", "schema": {"type": "integer"}}, "X-RateLimit-Remaining": {"description": "Requests left in this minute.", "schema": {"type": "integer"}}, "X-RateLimit-Reset": {"description": "Seconds until the minute resets.", "schema": {"type": "integer"}}, "Location": {"description": "URL of the new object.", "schema": {"type": "string"}}}}, "401": {"description": "Authentication required, Invalid token", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "403": {"description": "Insufficient scope, Account suspended, Writing through the API is turned off, Not allowed, Email confirmation required", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "429": {"description": "Too many requests, Posting limit reached", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "404": {"description": "Not found", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "422": {"description": "Invalid data, Looks like spam", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}}}}, "/api/v1/posts/{id}/vote": {"post": {"operationId": "vote", "summary": "Vote up, down, or take your vote back", "description": "Sets your vote to the given value (sending the same value twice changes nothing). The reputation needed for each direction, the votes per day and the time after which a vote can't be taken back are the site's. Needs a token with the write scope.", "tags": ["Votes"], "security": [{"bearerAuth": ["write"]}], "parameters": [{"name": "id", "in": "path", "required": true, "description": "The question or answer id.", "schema": {"type": "integer"}, "example": 1}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/VoteRequest"}, "example": {"vote": "up"}}}}, "responses": {"200": {"description": "OK.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Vote"}}}, "headers": {"X-RateLimit-Limit": {"description": "Requests allowed per minute.", "schema": {"type": "integer"}}, "X-RateLimit-Remaining": {"description": "Requests left in this minute.", "schema": {"type": "integer"}}, "X-RateLimit-Reset": {"description": "Seconds until the minute resets.", "schema": {"type": "integer"}}}}, "401": {"description": "Authentication required, Invalid token", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "403": {"description": "Insufficient scope, Account suspended, Writing through the API is turned off, Not allowed", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "429": {"description": "Too many requests, Posting limit reached", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "404": {"description": "Not found", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "409": {"description": "Conflict", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "422": {"description": "Invalid data", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}}}}, "/api/v1/answers/{id}/accept": {"post": {"operationId": "acceptAnswer", "summary": "Accept an answer", "description": "The site's limits on accepted answers per question apply. Accepting an accepted answer changes nothing. Needs a token with the write scope.", "tags": ["Answers"], "security": [{"bearerAuth": ["write"]}], "parameters": [{"name": "id", "in": "path", "required": true, "description": "The answer id.", "schema": {"type": "integer"}, "example": 1}], "responses": {"200": {"description": "OK.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Answer"}}}, "headers": {"X-RateLimit-Limit": {"description": "Requests allowed per minute.", "schema": {"type": "integer"}}, "X-RateLimit-Remaining": {"description": "Requests left in this minute.", "schema": {"type": "integer"}}, "X-RateLimit-Reset": {"description": "Seconds until the minute resets.", "schema": {"type": "integer"}}}}, "401": {"description": "Authentication required, Invalid token", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "403": {"description": "Insufficient scope, Account suspended, Writing through the API is turned off, Not allowed", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "429": {"description": "Too many requests", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "404": {"description": "Not found", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "409": {"description": "Conflict", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}}}, "delete": {"operationId": "unacceptAnswer", "summary": "Take an acceptance back", "description": "Needs a token with the write scope.", "tags": ["Answers"], "security": [{"bearerAuth": ["write"]}], "parameters": [{"name": "id", "in": "path", "required": true, "description": "The answer id.", "schema": {"type": "integer"}, "example": 1}], "responses": {"200": {"description": "OK.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Answer"}}}, "headers": {"X-RateLimit-Limit": {"description": "Requests allowed per minute.", "schema": {"type": "integer"}}, "X-RateLimit-Remaining": {"description": "Requests left in this minute.", "schema": {"type": "integer"}}, "X-RateLimit-Reset": {"description": "Seconds until the minute resets.", "schema": {"type": "integer"}}}}, "401": {"description": "Authentication required, Invalid token", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "403": {"description": "Insufficient scope, Account suspended, Writing through the API is turned off, Not allowed", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "429": {"description": "Too many requests", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "404": {"description": "Not found", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}}}}, "/api/v1/questions/{id}/follow": {"post": {"operationId": "followQuestion", "summary": "Follow a question", "description": "Get notified about its new answers and comments, as with the Follow button (by email as set in your email settings). Needs a token with the write scope.", "tags": ["Questions"], "security": [{"bearerAuth": ["write"]}], "parameters": [{"name": "id", "in": "path", "required": true, "description": "The question id.", "schema": {"type": "integer"}, "example": 1}], "responses": {"200": {"description": "OK.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Following"}}}, "headers": {"X-RateLimit-Limit": {"description": "Requests allowed per minute.", "schema": {"type": "integer"}}, "X-RateLimit-Remaining": {"description": "Requests left in this minute.", "schema": {"type": "integer"}}, "X-RateLimit-Reset": {"description": "Seconds until the minute resets.", "schema": {"type": "integer"}}}}, "401": {"description": "Authentication required, Invalid token", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "403": {"description": "Insufficient scope, Account suspended, Writing through the API is turned off, Not allowed", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "429": {"description": "Too many requests", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "404": {"description": "Not found", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}}}, "delete": {"operationId": "unfollowQuestion", "summary": "Stop following a question", "description": "Needs a token with the write scope.", "tags": ["Questions"], "security": [{"bearerAuth": ["write"]}], "parameters": [{"name": "id", "in": "path", "required": true, "description": "The question id.", "schema": {"type": "integer"}, "example": 1}], "responses": {"200": {"description": "OK.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Following"}}}, "headers": {"X-RateLimit-Limit": {"description": "Requests allowed per minute.", "schema": {"type": "integer"}}, "X-RateLimit-Remaining": {"description": "Requests left in this minute.", "schema": {"type": "integer"}}, "X-RateLimit-Reset": {"description": "Seconds until the minute resets.", "schema": {"type": "integer"}}}}, "401": {"description": "Authentication required, Invalid token", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "403": {"description": "Insufficient scope, Account suspended, Writing through the API is turned off, Not allowed", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "429": {"description": "Too many requests", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}, "404": {"description": "Not found", "content": {"application/problem+json": {"schema": {"$ref": "#/components/schemas/Problem"}}}}}}}}, "components": {"schemas": {"UserBrief": {"type": "object", "properties": {"id": {"type": "integer"}, "username": {"type": "string"}, "url": {"type": "string", "format": "uri"}, "reputation": {"type": "integer"}}, "required": ["id", "username", "url", "reputation"], "description": "A member, as shown next to posts."}, "User": {"type": "object", "properties": {"id": {"type": "integer"}, "username": {"type": "string"}, "url": {"type": "string", "format": "uri"}, "api_url": {"type": "string", "format": "uri"}, "reputation": {"type": "integer"}, "real_name": {"anyOf": [{"type": "string"}, {"type": "null"}]}, "location": {"anyOf": [{"type": "string"}, {"type": "null"}]}, "website": {"anyOf": [{"type": "string", "description": "Shown only once the member has enough reputation."}, {"type": "null"}]}, "badges": {"type": "object", "properties": {"gold": {"type": "integer"}, "silver": {"type": "integer"}, "bronze": {"type": "integer"}}, "required": ["gold", "silver", "bronze"]}, "joined": {"type": "string", "format": "date-time"}, "moderator": {"type": "boolean"}}, "required": ["id", "username", "url", "api_url", "reputation", "real_name", "location", "website", "badges", "joined", "moderator"], "description": "A public profile."}, "Me": {"type": "object", "properties": {"user": {"$ref": "#/components/schemas/User"}, "token": {"type": "object", "properties": {"name": {"type": "string"}, "scopes": {"type": "array", "items": {"enum": ["read", "write"]}}, "expires": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}]}}, "required": ["name", "scopes", "expires"]}}, "required": ["user", "token"]}, "QuestionSummary": {"type": "object", "properties": {"id": {"type": "integer"}, "url": {"type": "string", "format": "uri"}, "api_url": {"type": "string", "format": "uri"}, "title": {"type": "string"}, "tags": {"type": "array", "items": {"type": "string"}}, "score": {"type": "integer"}, "status": {"enum": ["unanswered", "answered", "accepted"]}, "answer_count": {"type": "integer"}, "view_count": {"type": "integer"}, "closed": {"type": "boolean"}, "duplicate_of": {"anyOf": [{"type": "object", "properties": {"id": {"type": "integer"}, "url": {"type": "string", "format": "uri"}, "api_url": {"type": "string", "format": "uri"}}, "required": ["id", "url", "api_url"]}, {"type": "null"}]}, "author": {"anyOf": [{"$ref": "#/components/schemas/UserBrief"}, {"type": "null"}]}, "created": {"type": "string", "format": "date-time"}, "last_activity": {"type": "string", "format": "date-time"}, "held_for_review": {"type": "boolean", "description": "Waiting for a moderator (shown to its author and moderators only; nobody else sees the post)."}}, "required": ["id", "url", "api_url", "title", "tags", "score", "status", "answer_count", "view_count", "closed", "duplicate_of", "author", "created", "last_activity", "held_for_review"]}, "PostVersion": {"type": "object", "properties": {"tag": {"type": "string"}, "version": {"type": "string", "description": "The version of the tagged product the post applies to."}, "current_version": {"anyOf": [{"type": "string", "description": "The tag's current version."}, {"type": "null"}]}, "outdated": {"type": "boolean", "description": "A newer version than the one it was written (or confirmed) for is current."}, "confirmed_for": {"anyOf": [{"type": "object", "properties": {"version": {"type": "string"}, "by": {"anyOf": [{"$ref": "#/components/schemas/UserBrief"}, {"type": "null"}]}, "at": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}]}}, "required": ["version", "by", "at"], "description": "Confirmed to still work in a newer version, without editing."}, {"type": "null"}]}}, "required": ["tag", "version", "current_version", "outdated", "confirmed_for"], "description": "The version of a tagged product a post applies to."}, "Comment": {"type": "object", "properties": {"id": {"type": "integer"}, "post_id": {"type": "integer"}, "url": {"type": "string", "format": "uri"}, "score": {"type": "integer"}, "author": {"anyOf": [{"$ref": "#/components/schemas/UserBrief"}, {"type": "null"}]}, "created": {"type": "string", "format": "date-time"}, "html": {"type": "string"}, "markdown": {"type": "string"}, "held_for_review": {"type": "boolean"}}, "required": ["id", "post_id", "url", "score", "author", "created", "html", "markdown", "held_for_review"]}, "Answer": {"type": "object", "properties": {"id": {"type": "integer"}, "question_id": {"type": "integer"}, "url": {"type": "string", "format": "uri"}, "api_url": {"type": "string", "format": "uri"}, "score": {"type": "integer"}, "accepted": {"type": "boolean"}, "author": {"anyOf": [{"$ref": "#/components/schemas/UserBrief"}, {"type": "null"}]}, "created": {"type": "string", "format": "date-time"}, "html": {"type": "string", "description": "The rendered, sanitised HTML shown on the site."}, "markdown": {"type": "string", "description": "The Markdown source."}, "held_for_review": {"type": "boolean"}, "versions": {"type": "array", "items": {"$ref": "#/components/schemas/PostVersion"}, "description": "The versions it applies to (empty when none is given)."}, "comments": {"type": "array", "items": {"$ref": "#/components/schemas/Comment"}}, "my_vote": {"anyOf": [{"enum": ["up", "down"]}, {"type": "null"}]}}, "required": ["id", "question_id", "url", "api_url", "score", "accepted", "author", "created", "html", "markdown", "held_for_review", "versions"]}, "Question": {"allOf": [{"$ref": "#/components/schemas/QuestionSummary"}, {"type": "object", "properties": {"html": {"type": "string"}, "markdown": {"type": "string"}, "deleted": {"type": "boolean"}, "versions": {"type": "array", "items": {"$ref": "#/components/schemas/PostVersion"}}, "comments": {"type": "array", "items": {"$ref": "#/components/schemas/Comment"}}, "answers": {"type": "array", "items": {"$ref": "#/components/schemas/Answer"}}, "my_vote": {"anyOf": [{"enum": ["up", "down"]}, {"type": "null"}]}, "following": {"type": "boolean"}}, "required": ["html", "markdown", "deleted", "versions", "comments", "answers"]}], "description": "A question with its answers (accepted first, then by score) and comments. my_vote and following are given when a token is sent."}, "Tag": {"type": "object", "properties": {"name": {"type": "string"}, "url": {"type": "string", "format": "uri"}, "api_url": {"type": "string", "format": "uri"}, "count": {"type": "integer", "description": "Questions with it."}, "description": {"type": "string", "description": "Markdown."}, "synonyms": {"type": "array", "items": {"type": "string"}, "description": "Names that are stored as this tag."}, "created": {"anyOf": [{"type": "string", "format": "date-time"}, {"type": "null"}]}}, "required": ["name", "url", "api_url", "count", "description", "synonyms", "created"]}, "Badge": {"type": "object", "properties": {"id": {"type": "integer"}, "name": {"type": "string"}, "description": {"type": "string"}, "type": {"enum": ["gold", "silver", "bronze"]}, "awarded_count": {"type": "integer"}, "url": {"type": "string", "format": "uri"}}, "required": ["id", "name", "description", "type", "awarded_count", "url"]}, "Vote": {"type": "object", "properties": {"post_id": {"type": "integer"}, "vote": {"anyOf": [{"enum": ["up", "down"]}, {"type": "null"}]}, "score": {"type": "integer"}, "votes_left": {"type": "integer", "description": "Votes you can still cast in the next 24 hours."}}, "required": ["post_id", "vote", "score", "votes_left"]}, "Following": {"type": "object", "properties": {"question_id": {"type": "integer"}, "following": {"type": "boolean"}}, "required": ["question_id", "following"]}, "Index": {"type": "object", "properties": {"name": {"type": "string"}, "version": {"type": "string"}, "docs": {"type": "string", "format": "uri"}, "openapi": {"type": "string", "format": "uri"}, "links": {"type": "object", "additionalProperties": {"type": "string", "format": "uri"}}}, "required": ["name", "version", "docs", "openapi", "links"]}, "Problem": {"type": "object", "description": "An error (RFC 9457, application/problem+json).", "properties": {"type": {"type": "string", "format": "uri"}, "title": {"type": "string"}, "status": {"type": "integer"}, "detail": {"type": "string"}, "instance": {"type": "string"}, "errors": {"type": "object", "additionalProperties": {"type": "array", "items": {"type": "string"}}, "description": "Messages per field or parameter (validation-error, bad-request)."}}, "required": ["type", "title", "status"]}, "QuestionPage": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/QuestionSummary"}}, "next": {"anyOf": [{"type": "string", "format": "uri"}, {"type": "null"}]}}, "required": ["data", "next"], "description": "A list: the items, and the URL of the next page (null on the last page)."}, "AnswerList": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/Answer"}}, "next": {"anyOf": [{"type": "string", "format": "uri"}, {"type": "null"}]}}, "required": ["data", "next"], "description": "A list: the items, and the URL of the next page (null on the last page)."}, "TagPage": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/Tag"}}, "next": {"anyOf": [{"type": "string", "format": "uri"}, {"type": "null"}]}}, "required": ["data", "next"], "description": "A list: the items, and the URL of the next page (null on the last page)."}, "UserPage": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/User"}}, "next": {"anyOf": [{"type": "string", "format": "uri"}, {"type": "null"}]}}, "required": ["data", "next"], "description": "A list: the items, and the URL of the next page (null on the last page)."}, "BadgeList": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/Badge"}}, "next": {"anyOf": [{"type": "string", "format": "uri"}, {"type": "null"}]}}, "required": ["data", "next"], "description": "A list: the items, and the URL of the next page (null on the last page)."}, "NewQuestion": {"type": "object", "properties": {"title": {"type": "string"}, "text": {"type": "string", "description": "Markdown."}, "tags": {"anyOf": [{"type": "array", "items": {"type": "string"}}, {"type": "string"}], "description": "Tag names (a list, or one string separated by spaces)."}, "wiki": {"type": "boolean", "description": "Community wiki (when the site allows it)."}}, "required": ["title", "text", "tags"]}, "NewAnswer": {"type": "object", "properties": {"text": {"type": "string", "description": "Markdown."}, "wiki": {"type": "boolean"}}, "required": ["text"]}, "NewComment": {"type": "object", "properties": {"text": {"type": "string"}}, "required": ["text"]}, "VoteRequest": {"type": "object", "properties": {"vote": {"enum": ["up", "down", "none"], "description": "none takes your vote back."}}, "required": ["vote"]}}, "securitySchemes": {"bearerAuth": {"type": "http", "scheme": "bearer", "description": "A personal access token, created on your account page (Settings > API tokens). Scopes: read, write."}}}, "externalDocs": {"url": "https://openforis.support/api/", "description": "API documentation"}, "x-problem-types": {"bad-request": {"type": "https://openforis.support/api/#problem-bad-request", "status": 400, "title": "Bad request"}, "unauthorized": {"type": "https://openforis.support/api/#problem-unauthorized", "status": 401, "title": "Authentication required"}, "invalid-token": {"type": "https://openforis.support/api/#problem-invalid-token", "status": 401, "title": "Invalid token"}, "insufficient-scope": {"type": "https://openforis.support/api/#problem-insufficient-scope", "status": 403, "title": "Insufficient scope"}, "forbidden": {"type": "https://openforis.support/api/#problem-forbidden", "status": 403, "title": "Not allowed"}, "account-suspended": {"type": "https://openforis.support/api/#problem-account-suspended", "status": 403, "title": "Account suspended"}, "email-confirmation-required": {"type": "https://openforis.support/api/#problem-email-confirmation-required", "status": 403, "title": "Email confirmation required"}, "captcha-required": {"type": "https://openforis.support/api/#problem-captcha-required", "status": 403, "title": "Use the web site"}, "writes-disabled": {"type": "https://openforis.support/api/#problem-writes-disabled", "status": 403, "title": "Writing through the API is turned off"}, "not-found": {"type": "https://openforis.support/api/#problem-not-found", "status": 404, "title": "Not found"}, "method-not-allowed": {"type": "https://openforis.support/api/#problem-method-not-allowed", "status": 405, "title": "Method not allowed"}, "conflict": {"type": "https://openforis.support/api/#problem-conflict", "status": 409, "title": "Conflict"}, "payload-too-large": {"type": "https://openforis.support/api/#problem-payload-too-large", "status": 413, "title": "Request body too large"}, "unsupported-media-type": {"type": "https://openforis.support/api/#problem-unsupported-media-type", "status": 415, "title": "Unsupported media type"}, "validation-error": {"type": "https://openforis.support/api/#problem-validation-error", "status": 422, "title": "Invalid data"}, "spam": {"type": "https://openforis.support/api/#problem-spam", "status": 422, "title": "Looks like spam"}, "rate-limited": {"type": "https://openforis.support/api/#problem-rate-limited", "status": 429, "title": "Too many requests"}, "posting-limit": {"type": "https://openforis.support/api/#problem-posting-limit", "status": 429, "title": "Posting limit reached"}, "server-error": {"type": "https://openforis.support/api/#problem-server-error", "status": 500, "title": "Server error"}, "api-disabled": {"type": "https://openforis.support/api/#problem-api-disabled", "status": 503, "title": "The API is turned off"}}}