openapi: 3.0.0 servers: - url: https://plagiarismcheck.org/ description: Production server info: description: | PlagiarismCheck.org API for individual users and organizations. Use this specification to submit plagiarism and AI checks, monitor processing status, fetch reports, and manage group resources. The `/api/v2` endpoints are available for formatted documents: they parse and save document formatting assets so clients can validate formatted content, submit it for checking, and retrieve stored markup later. More integration details are available on the [developer page](https://plagiarismcheck.org/for-developers/) and in the [API examples repository](https://github.com/PlagiarismCheck/api-examples). version: "1.0.0" title: PlagiarismCheck.org API contact: email: jane.adelmann@plagiarismcheck.org license: name: Apache 2.0 url: 'https://www.apache.org/licenses/LICENSE-2.0.html' tags: - name: Individuals description: "Endpoints for individual user accounts: submit texts, check status, retrieve reports, and manage personal checks." - name: Formatted Documents description: Endpoints under `/api/v2` for formatted documents. Use them when document formatting must be parsed, saved, validated, submitted for checking, and retrieved as markup. - name: Organizations description: Endpoints for organization and LMS integrations that authenticate with a group token. - name: AI Detection description: Endpoints for standalone AI-generated text detection checks. - name: Groups description: Groups represent schools, universities, or other organizations. A group contains members, balance settings, usage limits, and check preferences. - name: Group Members description: Endpoints for managing group members, including students, teachers, and owners. - name: Reports description: Endpoints for report edits, filters, and report-related utility actions. - name: Extension Reports description: Endpoints used by browser extension report-data integrations. - name: Fingerprint description: Endpoints for AI fingerprint profile checks and related feedback. - name: Folders description: Endpoints for organizing texts and documents into group folders and folder shares. - name: Agreements description: Endpoints for accepting and listing user agreements. - name: Integrations description: Endpoints for LMS integration state and classroom subscription actions. - name: OneRoster description: Endpoints for configuring and triggering OneRoster FTP-based roster synchronisation. Group owners configure an FTP/FTPS endpoint that holds `enrollments.csv` and `users.csv` files; the sync reads those files and creates, updates, or removes group members accordingly. - name: Search Settings description: Endpoints for reading and saving user search settings. - name: User description: Endpoints for user email verification, user reviews, and user actions. - name: Grammar Check description: Endpoints for grammar-check activation, submission, and report retrieval. - name: Subscriptions description: Endpoints for user and group subscription details. - name: LTI Tool Deployment description: Endpoints for registering and listing LTI 1.3 tool deployments. - name: Rubrics description: Endpoints for rubric retrieval and rubric grading. - name: Submission Grades description: Endpoints for reading and saving submission grades. - name: Tools description: Endpoints for auxiliary API-backed tools. security: - ApiTokenHeader: [] paths: /api/v1/text: post: operationId: createTextCheck tags: - Individuals summary: Submit text for plagiarism checking description: | Submit plain text or a supported file for plagiarism checking. The authenticated user is charged against either their own balance or the selected group balance. The text must pass content and language validation, and duplicate submissions within a short interval are rejected. When the external checking queue cannot accept the text immediately, the check may be stored and submitted by background processing. requestBody: $ref: '#/components/requestBodies/TextCreateRequest' responses: '201': $ref: '#/components/responses/TextCreated' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '409': $ref: '#/components/responses/Conflict' '429': $ref: '#/components/responses/RateLimited' /api/v1/text/{textId}: get: operationId: getTextStatus tags: - Individuals summary: Get text check status description: | Return metadata for a text check, including processing state, page/word counts, report summary, creator, and AI report when available. Deleted texts are not returned. parameters: - $ref: '#/components/parameters/TextCheckIdPath' responses: '200': $ref: '#/components/responses/SuccessWithTextData' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' delete: operationId: deleteText tags: - Individuals summary: Delete a text check description: | Mark a single text check as deleted. The record remains in storage but is hidden from normal API results. parameters: - $ref: '#/components/parameters/TextCheckIdPath' responses: '200': $ref: '#/components/responses/SuccessOnly' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/text/report/{textId}: get: operationId: getTextReport tags: - Individuals summary: Get report by text ID description: | Return the plagiarism report attached to a text check. If the check is not finished or parsed report data is unavailable, the endpoint still returns `200` with `success: false`, `report_data: null`, and a warning message. parameters: - $ref: '#/components/parameters/TextCheckIdPath' responses: '200': $ref: '#/components/responses/SuccessWithReportData' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/texts/: get: operationId: listTexts tags: - Individuals summary: List text checks description: | Return a paginated list of text checks owned by the authenticated user. Use `page`, `size`, and `search` to browse larger histories. parameters: - $ref: '#/components/parameters/SearchQuery' - $ref: '#/components/parameters/PageQuery' - $ref: '#/components/parameters/SizeQuery' responses: '200': $ref: '#/components/responses/SuccessWithTextsList' '403': $ref: '#/components/responses/Forbidden' /api/v1/texts: delete: operationId: deleteTexts tags: - Individuals summary: Delete multiple text checks description: | Mark multiple text checks as deleted in one request. Send the IDs as an array form field named `id[]`. Every submitted ID must be a positive integer and must identify a text the authenticated user is allowed to delete. requestBody: $ref: '#/components/requestBodies/TextsDeleteRequest' responses: '200': $ref: '#/components/responses/SuccessOnly' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/report/{reportId}: get: operationId: getReport tags: - Individuals summary: Get report by report ID description: | Return a plagiarism report directly by report ID, including report metadata and parsed report data when available. Reports for deleted texts are treated as not found. parameters: - $ref: '#/components/parameters/ReportIdPath' responses: '200': $ref: '#/components/responses/SuccessWithReportData' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v2/text/: post: operationId: createFormattedTextCheck tags: - Formatted Documents summary: Submit formatted text for checking description: | Submit plain text or an uploaded file for the formatted text checking flow. The endpoint extracts formatted text assets, stores the original text, submits the check, and charges the authenticated user or selected group. Send either a `text` form field or an uploaded file in the `text` multipart field. The submitted content must pass formatted-text processing, minimum length, maximum length (1048576 symbols, counted on the processed text), balance, group membership, and duplicate-in-progress checks. The maximum length is enforced here as well as by `/api/v2/text/validate/`, so it applies whether or not the validate endpoint was called first. If a `Referer` header points to `https://plagiarismcheck.org`, the created text is also linked to the site integration. requestBody: $ref: '#/components/requestBodies/FormattedTextCreateRequest' responses: '201': $ref: '#/components/responses/FormattedTextCreated' '400': $ref: '#/components/responses/SubmissionFailed' '403': $ref: '#/components/responses/Forbidden' /api/v2/text/markup/{id}/: get: operationId: getFormattedTextMarkup tags: - Formatted Documents summary: Get formatted text markup description: | Return stored formatted markup for a checked formatted text, including rendered HTML, the parsed map JSON, and the plain text used for the report. The text must exist, must not be deleted, must be readable by the authenticated user, and must have formatted report assets available. Non-formatted texts and missing markup/map/plain-text assets return a validation error. parameters: - $ref: '#/components/parameters/TextIdPath' responses: '200': $ref: '#/components/responses/SuccessWithFormattedMarkup' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v2/text/validate/: post: operationId: validateFormattedTextCheck tags: - Formatted Documents summary: Validate formatted text description: | Validate plain text or an uploaded file before submitting it for a formatted text check. The endpoint parses the content, counts words and pages, checks UTF-8 and text length constraints, and applies language/letter-percentage validation. A text over the maximum length (1048576 symbols) is a blocking failure returned with `code: 5`, `words` and `pages`. It is not affected by `skip_english_words_validation` or `skip_percentage_words_validation`, which waive the language and letter-percentage rules only. This endpoint does not charge the account or create a text check. If `group_id` is supplied and the group disables language validation, the language and letter-percentage validations are skipped. requestBody: $ref: '#/components/requestBodies/FormattedTextValidateRequest' responses: '200': $ref: '#/components/responses/SuccessWithFormattedTextValidation' '400': $ref: '#/components/responses/FormattedTextValidationFailed' '403': $ref: '#/components/responses/Forbidden' /api/org/text/check/: post: operationId: createOrgTextCheck tags: - Organizations security: [] summary: Submit an organization text check description: | Submit plain text or a supported file on behalf of an organization member. The organization is authorized by the `group_token` form field and the check is owned by the group member whose email is passed in `author`. The token must start with `G-`, the group must be active, and `author` must already belong to the group. `callback` is stored with the check and called after processing by the group API integration. requestBody: $ref: '#/components/requestBodies/OrgTextCheckRequest' responses: '201': $ref: '#/components/responses/SuccessWithOrgText' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/org/text/status/{id}/: post: operationId: getOrgTextStatus tags: - Organizations security: [] summary: Get organization text status description: | Return the current processing status for an organization text check. Poll this endpoint until the text reaches a terminal state such as checked or failed. The `group_token` form field must identify the same active group that owns the text. parameters: - $ref: '#/components/parameters/TextIdPath' requestBody: $ref: '#/components/requestBodies/OrgTokenRequest' responses: '200': $ref: '#/components/responses/SuccessWithTextDataAndSuccess' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/org/text/report/{id}/: post: operationId: getOrgTextReport tags: - Organizations security: [] summary: Get organization text report description: | Return the plagiarism report for an organization text check by text ID. The text must belong to the group authorized by `group_token` and must already be checked. parameters: - $ref: '#/components/parameters/TextIdPath' requestBody: $ref: '#/components/requestBodies/OrgTokenRequest' responses: '200': $ref: '#/components/responses/SuccessWithReportDataAndSuccess' '400': $ref: '#/components/responses/BadRequest' '404': $ref: '#/components/responses/NotFound' /api/org/text/delete/{id}/: post: operationId: deleteOrgText tags: - Organizations security: [] summary: Delete organization text description: | Mark an organization text check as deleted. The text must belong to the group authorized by `group_token`; already deleted texts return a business-rule error. parameters: - $ref: '#/components/parameters/TextIdPath' requestBody: $ref: '#/components/requestBodies/OrgTokenRequest' responses: '200': $ref: '#/components/responses/SuccessOnly' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/org/group/has-member/: post: operationId: checkGroupHasMember tags: - Organizations security: [] summary: Check whether an email belongs to a group description: | Check whether an email address is already a member of the group authorized by `group_token`. The response also tells clients whether the group allows integration-driven auto-registration. requestBody: $ref: '#/components/requestBodies/OrgHasMemberRequest' responses: '200': $ref: '#/components/responses/SuccessWithHasMember' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/org/group/auto-registration/: post: operationId: autoRegisterGroupMember tags: - Organizations security: [] summary: Auto-register a group member description: | Create a group member through an organization integration. The `role` form field accepts only teacher (`2`) or student (`3`); owner (`1`) is not allowed. requestBody: $ref: '#/components/requestBodies/OrgAutoRegistrationRequest' responses: '200': $ref: '#/components/responses/SuccessWithMemberId' '400': $ref: '#/components/responses/BadRequest' /api/v1/chat-gpt/: post: operationId: createAiCheck tags: - AI Detection summary: Submit text for AI detection description: | Submit text or a supported file for AI-generated text detection. The response contains the created AI check report. The authenticated user must be allowed to create AI checks. The endpoint rejects empty content, content below the configured minimum character length, disabled AI-check settings, missing AI package eligibility, and texts over the configured free or paid word limits. requestBody: $ref: '#/components/requestBodies/AiCheckCreateRequest' responses: '200': $ref: '#/components/responses/SuccessWithAiCheck' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/chat-gpt/validate/: post: operationId: validateAiCheck tags: - AI Detection summary: Validate text for AI detection description: | Validate text or a supported file before creating an AI detection check. The endpoint parses the submitted content, applies the same pre-check validation rules and configured length limits as `POST /api/v1/chat-gpt/`, and returns the calculated size in words and pages. This endpoint does not create a report, queue a check, save an original file, or charge the account. requestBody: $ref: '#/components/requestBodies/AiCheckCreateRequest' responses: '200': $ref: '#/components/responses/SuccessWithAiCheckValidation' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/chat-gpt/{id}/: get: operationId: getAiCheckResult tags: - AI Detection summary: Get AI detection result description: | Return an AI detection report by ID, including status, percentages, saved feedback, and highlighted chunks. The report must be a ChatGPT/perplexity report owned by or visible to the authenticated user. parameters: - $ref: '#/components/parameters/TextIdPath' responses: '200': $ref: '#/components/responses/SuccessWithAiCheckResult' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/chat-gpt/mark/{id}/: post: operationId: markAiCheckResult tags: - AI Detection summary: Rate an AI detection result description: "Save user feedback for an AI detection result. Send `mark=1` for like or `mark=0` for dislike, with an optional comment." parameters: - $ref: '#/components/parameters/TextIdPath' requestBody: $ref: '#/components/requestBodies/AiCheckMarkRequest' responses: '201': $ref: '#/components/responses/AiFeedbackSaved' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/groups/list/: get: operationId: listGroups tags: - Groups summary: List groups for current user description: "Return every group where the authenticated user is a member." responses: '200': $ref: '#/components/responses/SuccessWithGroups' '403': $ref: '#/components/responses/Forbidden' /api/v1/groups/view/{id}/: get: operationId: getGroupView tags: - Groups summary: Get group details description: | Return basic group details, owner contact information, and current group balance. The authenticated user must be a member of the group. parameters: - $ref: '#/components/parameters/GroupIdPath' responses: '200': $ref: '#/components/responses/SuccessWithGroupView' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/groups/transactions/{id}/: get: operationId: getGroupTransactions tags: - Groups summary: List group balance transactions description: | Return paginated balance transactions for a group. The authenticated user must be allowed to view the group. Use `search` or `userId` to filter the transaction history. parameters: - $ref: '#/components/parameters/GroupIdPath' - $ref: '#/components/parameters/SearchQuery' - $ref: '#/components/parameters/UserIdQuery' - $ref: '#/components/parameters/PageQuery' - $ref: '#/components/parameters/SizeQuery' responses: '200': $ref: '#/components/responses/SuccessWithTransactions' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/groups/members/{id}/: get: operationId: listGroupMembers tags: - Group Members summary: List group members description: | Return a paginated list of members in a group. The authenticated user must be allowed to view the group. Use `search` and `filterId` to narrow results. parameters: - $ref: '#/components/parameters/GroupIdPath' - $ref: '#/components/parameters/SearchQuery' - $ref: '#/components/parameters/FilterIdQuery' - $ref: '#/components/parameters/PageQuery' - $ref: '#/components/parameters/SizeQuery' responses: '200': $ref: '#/components/responses/SuccessWithMembers' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/groups/add-member/{id}/: post: operationId: addGroupMember tags: - Group Members summary: Add a group member description: | Add a teacher or student to a group. Only a group owner can add members. If no user exists for the submitted email, the application creates one and adds it to the group. parameters: - $ref: '#/components/parameters/GroupIdPath' requestBody: $ref: '#/components/requestBodies/GroupMemberCreateRequest' responses: '201': $ref: '#/components/responses/SuccessWithMember' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/groups/remove-member/{id}/: delete: operationId: removeGroupMember tags: - Group Members summary: Remove a group member description: | Remove a member from the group. Only group owners can remove members, and business rules may block removal of some members. parameters: - $ref: '#/components/parameters/MemberIdPath' responses: '200': $ref: '#/components/responses/GroupMemberRemoved' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/groups/edit-member/{id}/: post: operationId: updateGroupMember tags: - Group Members summary: Update a group member description: | Update a member's role and page limit. Only group owners can update members. Send `limit=no limit` to clear an existing member limit. parameters: - $ref: '#/components/parameters/MemberIdPath' requestBody: $ref: '#/components/requestBodies/GroupMemberUpdateRequest' responses: '200': $ref: '#/components/responses/SuccessWithMember' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/documents/: get: operationId: getDocumentsList tags: - Individuals summary: List plagiarism and AI checks description: | Return a combined list of plagiarism checks and AI detection checks for the authenticated user. parameters: - $ref: '#/components/parameters/SearchQuery' - $ref: '#/components/parameters/DocumentTypesQuery' - $ref: '#/components/parameters/PageQuery' - $ref: '#/components/parameters/SizeQuery' responses: '200': $ref: '#/components/responses/SuccessWithTextDatas' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/text/validate: post: operationId: validateTextCheck tags: - Individuals summary: Validate text before checking description: | Validate plain text or an uploaded file before creating a plagiarism check. The endpoint uses the same authentication and validation rules as text creation but does not create a final check. requestBody: $ref: '#/components/requestBodies/TextCreateRequest' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/texts/{userId}/{lastTextId}: get: operationId: listTextsByUserCursor tags: - Individuals summary: List texts by user cursor description: "Return text checks for a user, optionally starting after `lastTextId`. This legacy route is registered alongside `/api/v1/texts/`." parameters: - $ref: '#/components/parameters/UserIdPath' - $ref: '#/components/parameters/LastTextIdPath' responses: '200': $ref: '#/components/responses/SuccessWithTextsList' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/archive/: post: operationId: getArchive tags: - Individuals summary: Get archived content description: "Return archived source content for the authenticated user. The exact lookup parameters are request-body fields handled by the archive controller." requestBody: $ref: '#/components/requestBodies/GenericFormRequest' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/report/save-changes/{id}/: post: operationId: saveReportChanges tags: - Reports summary: Save report changes description: "Save user changes to a parsed plagiarism report, such as enabled or disabled matches. The report must belong to a text visible to the authenticated user." parameters: - $ref: '#/components/parameters/IdPath' requestBody: $ref: '#/components/requestBodies/GenericJsonRequest' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/report/apply-filters/{id}/: post: operationId: applyReportFilters tags: - Reports summary: Apply report filters description: "Apply plagiarism-report filters and return recalculated report data for a report visible to the authenticated user." parameters: - $ref: '#/components/parameters/IdPath' requestBody: $ref: '#/components/requestBodies/GenericJsonRequest' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/extension/reports/: get: operationId: listExtensionReports tags: - Extension Reports summary: List extension reports description: "Return a paginated list of Integrito report-data records owned by the authenticated user, ordered by ID descending." parameters: - $ref: '#/components/parameters/PageQuery' - $ref: '#/components/parameters/SizeQuery' responses: '200': $ref: '#/components/responses/ExtensionReportListResponse' '403': $ref: '#/components/responses/Forbidden' post: operationId: createExtensionReport tags: - Extension Reports summary: Create extension report description: "Create a new Integrito report-data record. `created_at` is set to the current server time and cannot be overridden. Returns `400` if `item_id` is already used by another record owned by the authenticated user. Returns `403` if the referenced text exists but belongs to another user. Returns `404` if the referenced text does not exist." requestBody: $ref: '#/components/requestBodies/ExtensionReportWriteRequest' responses: '201': $ref: '#/components/responses/ExtensionReportResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/extension/reports/{id}/: parameters: - $ref: '#/components/parameters/IdPath' get: operationId: getExtensionReport tags: - Extension Reports summary: Get extension report description: "Return one Integrito report-data record by ID. Returns `403` if the record exists but belongs to another user's text. Returns `404` if no record with the given ID exists." responses: '200': $ref: '#/components/responses/ExtensionReportResponse' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' put: operationId: updateExtensionReport tags: - Extension Reports summary: Update extension report description: "Replace all fields on an existing Integrito report-data record. `created_at` is preserved; `updated_at` is set to the current server time. Returns `400` if `item_id` is already used by a different record owned by the authenticated user. Returns `403` if the record or the new `text_id` exists but belongs to another user. Returns `404` if the record or the new `text_id` does not exist." requestBody: $ref: '#/components/requestBodies/ExtensionReportWriteRequest' responses: '200': $ref: '#/components/responses/ExtensionReportResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' delete: operationId: deleteExtensionReport tags: - Extension Reports summary: Delete extension report description: "Permanently delete one Integrito report-data record. Returns `403` if the record exists but belongs to another user's text. Returns `404` if no record with the given ID exists." responses: '200': $ref: '#/components/responses/SuccessOnly' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/extension/reports/batch-upsert/: post: operationId: batchUpsertExtensionReports tags: - Extension Reports summary: Batch upsert extension reports description: "Create or update multiple Integrito report-data records in one request. Each item in the JSON array may include an optional `id` and/or `item_id` field. When `id` is present, the matching record is updated by id and `item_id` (if provided) is written as the new value. When `id` is absent but `item_id` is provided, the record owned by the current user with that `item_id` is updated, or a new record is created with that `item_id` when none matches. When both are absent, a new record is created. `updated_at` is set to the current server time on updates; `created_at` is set on creates. Returns `201 CREATED` if at least one item was newly created; returns `200 OK` if all items were updates. Returns `400` if any `item_id` collides with another record owned by the authenticated user or appears more than once for distinct records inside the batch. Returns `403` if any referenced text or report `id` exists but belongs to another user. Returns `404` if any referenced text or report `id` does not exist." requestBody: $ref: '#/components/requestBodies/ExtensionReportBatchUpsertRequest' responses: '200': $ref: '#/components/responses/ExtensionReportBatchResponse' '201': $ref: '#/components/responses/ExtensionReportBatchResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/integrito/shared/: get: operationId: listSharedIntegritoReports tags: - Integrito summary: List reports shared with the current user description: "Return the list of Integrito reports that have been shared with the authenticated user." responses: '200': $ref: '#/components/responses/GenericDataResponse' '403': $ref: '#/components/responses/Forbidden' /api/v1/integrito/: get: operationId: listIntegritoReports tags: - Integrito summary: List Integrito reports description: "Return all Integrito reports created by the authenticated user." responses: '200': $ref: '#/components/responses/GenericDataResponse' '403': $ref: '#/components/responses/Forbidden' post: operationId: createIntegritoReport tags: - Integrito summary: Create Integrito report description: "Save a new Integrito report. `name` and `data` (JSON string) are required." requestBody: $ref: '#/components/requestBodies/GenericFormRequest' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/integrito/{id}/: parameters: - $ref: '#/components/parameters/IdPath' get: operationId: getIntegritoReport tags: - Integrito summary: Get Integrito report description: "Return a single Integrito report by ID, including the saved report data." responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' put: operationId: updateIntegritoReport tags: - Integrito summary: Update Integrito report description: "Update the `name` and/or `data` of an existing Integrito report." requestBody: $ref: '#/components/requestBodies/GenericFormRequest' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/integrito/{id}/share/: parameters: - $ref: '#/components/parameters/IdPath' post: operationId: shareIntegritoReport tags: - Integrito summary: Share Integrito report description: "Share an Integrito report with another user by email address. Returns the share ID and a registration URL for the recipient." requestBody: $ref: '#/components/requestBodies/GenericFormRequest' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/fingerprint/text-status/{id}/: get: operationId: getFingerprintTextStatus tags: - Fingerprint summary: Get fingerprint text status description: "Return the AI fingerprint status and report metadata for a text visible to the authenticated user." parameters: - $ref: '#/components/parameters/IdPath' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/fingerprint/send-text/{id}/: post: operationId: sendFingerprintText tags: - Fingerprint summary: Send text for fingerprint checking description: "Submit a text to the AI fingerprint service. The text must be visible to the authenticated user and eligible for fingerprint checking." parameters: - $ref: '#/components/parameters/IdPath' requestBody: $ref: '#/components/requestBodies/GenericFormRequest' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/fingerprint/mark/{id}/: post: operationId: markFingerprintReport tags: - Fingerprint summary: Rate fingerprint result description: "Save user feedback for a fingerprint result." parameters: - $ref: '#/components/parameters/IdPath' requestBody: $ref: '#/components/requestBodies/AiCheckMarkRequest' responses: '201': $ref: '#/components/responses/AiFeedbackSaved' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/folders/list/: get: operationId: listFolders tags: - Folders summary: List folders description: "Return folders visible to the authenticated user, usually scoped by group or parent-folder request parameters." parameters: - $ref: '#/components/parameters/GroupIdQuery' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/folders/create/: get: operationId: createFolderWithQuery tags: - Folders summary: Create folder with query parameters description: "Create a group folder using query parameters. `groupId` and `name` are required by the folder controller." parameters: - $ref: '#/components/parameters/GroupIdQuery' responses: '201': $ref: '#/components/responses/GenericCreated' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' post: operationId: createFolder tags: - Folders summary: Create folder description: "Create a group folder. `groupId` and `name` are required; `description` and `parent` are optional when supported by the folder controller." requestBody: $ref: '#/components/requestBodies/FolderCreateRequest' responses: '201': $ref: '#/components/responses/GenericCreated' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/folders/update/{id}/: parameters: - $ref: '#/components/parameters/IdPath' post: operationId: updateFolder tags: - Folders summary: Update folder description: "Update folder metadata such as name, description, or parent." requestBody: $ref: '#/components/requestBodies/FolderUpdateRequest' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' patch: operationId: patchFolder tags: - Folders summary: Patch folder description: "Update folder metadata using the PATCH method." requestBody: $ref: '#/components/requestBodies/FolderUpdateRequest' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/folders/delete/{id}/: delete: operationId: deleteFolder tags: - Folders summary: Delete folder description: "Delete a folder visible to the authenticated user. Business rules may reject deletion when the folder cannot be removed." parameters: - $ref: '#/components/parameters/IdPath' responses: '200': $ref: '#/components/responses/SuccessOnly' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/folders/move/{id}/{folderId}/: parameters: - $ref: '#/components/parameters/IdPath' - $ref: '#/components/parameters/FolderIdPath' get: operationId: moveTextToFolderWithGet tags: - Folders summary: Move text to folder with GET description: "Move a text or document into a folder using the legacy GET route." responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' post: operationId: moveTextToFolder tags: - Folders summary: Move text to folder description: "Move a text or document into a folder." responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/folders/move-to-root/{id}/: parameters: - $ref: '#/components/parameters/IdPath' get: operationId: moveTextToRootWithGet tags: - Folders summary: Move text to root with GET description: "Move a text or document out of folders using the legacy GET route." responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' post: operationId: moveTextToRoot tags: - Folders summary: Move text to root description: "Move a text or document out of folders." responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/folders/share/{id}/: parameters: - $ref: '#/components/parameters/IdPath' get: operationId: shareFolderWithGet tags: - Folders summary: Share folder with GET description: "Share a folder using legacy query parameters. Teachers and owners can share folders with other group members." responses: '201': $ref: '#/components/responses/GenericCreated' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' post: operationId: shareFolder tags: - Folders summary: Share folder description: "Share a folder with another group member." requestBody: $ref: '#/components/requestBodies/GenericFormRequest' responses: '201': $ref: '#/components/responses/GenericCreated' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/folders-shares/delete/{id}/: delete: operationId: deleteFolderShare tags: - Folders summary: Delete folder share description: "Remove a folder share visible to the authenticated user." parameters: - $ref: '#/components/parameters/IdPath' responses: '200': $ref: '#/components/responses/SuccessOnly' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/groups/create/: post: operationId: createGroup tags: - Groups summary: Create group description: "Create a group and add the authenticated user as owner. `name` is required." requestBody: $ref: '#/components/requestBodies/GroupCreateRequest' responses: '200': $ref: '#/components/responses/SuccessWithGroup' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/groups/{id}/update/: post: operationId: updateGroup tags: - Groups summary: Update group description: "Update group settings. The authenticated user must be allowed to manage the group." parameters: - $ref: '#/components/parameters/IdPath' requestBody: $ref: '#/components/requestBodies/GenericFormRequest' responses: '200': $ref: '#/components/responses/SuccessWithGroup' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/groups/{id}/delete/: delete: operationId: deleteGroup tags: - Groups summary: Delete group description: "Delete or disable a group. The authenticated user must be allowed to manage the group." parameters: - $ref: '#/components/parameters/IdPath' responses: '200': $ref: '#/components/responses/SuccessOnly' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/groups/subscriptions/{id}/: get: operationId: listGroupSubscriptions tags: - Subscriptions summary: List group subscriptions description: "Return subscription details for a group visible to the authenticated user." parameters: - $ref: '#/components/parameters/IdPath' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/groups/oneroster-sync-data/{id}/: parameters: - $ref: '#/components/parameters/IdPath' get: operationId: getOneRosterSyncData tags: - OneRoster summary: Get OneRoster sync configuration description: | Return the OneRoster sync configuration record for the given group. The authenticated user must be an owner of the group. When no configuration has been saved yet, `data` is returned with all fields set to `null`. responses: '200': $ref: '#/components/responses/OneRosterSyncDataResponse' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' post: operationId: setupOneRosterSyncData tags: - OneRoster summary: Save OneRoster sync configuration description: | Create or update the OneRoster FTP sync configuration for a group. The authenticated user must be an owner of the group. The supplied `url` must be a valid `ftp://` or `ftps://` URL. When `enabled` is `true` (the default), the server tests the connection immediately and returns `400` if it cannot connect. When `enabled` is `false` the record is saved with status `2` (disabled) without attempting a connection test. Status values returned in the response: - `1` — error (last sync failed or connection test failed) - `2` — disabled - `3` — ok / enabled requestBody: $ref: '#/components/requestBodies/OneRosterSyncSetupRequest' responses: '200': $ref: '#/components/responses/OneRosterSyncDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/groups/oneroster-sync/{id}/: post: operationId: syncOneRosterGroup tags: - OneRoster summary: Run OneRoster sync manually description: | Trigger an immediate OneRoster roster synchronisation for the given group. The authenticated user must be an owner of the group and a saved, enabled sync configuration must exist. The server reads `enrollments.csv` and `users.csv` from the configured FTP endpoint and creates, updates, or removes group members accordingly. OneRoster roles are mapped as follows: `student` → student member, `teacher` → teacher member, `administrator` → owner member. Returns `400` when no configuration exists, the FTP connection fails, the CSV files are missing or empty, or a file contains more than 1 000 records. parameters: - $ref: '#/components/parameters/IdPath' responses: '200': $ref: '#/components/responses/OneRosterSyncDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/groups/registration-link/create/{group_id}/{role_id}/: post: operationId: createGroupRegistrationLink tags: - Groups summary: Create group registration link description: "Create a registration link for adding users to a group with a selected role." parameters: - $ref: '#/components/parameters/GroupIdUnderscorePath' - $ref: '#/components/parameters/RoleIdPath' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/groups/texts/{id}/folders/{folderId}/: get: operationId: listGroupFolderTexts tags: - Folders summary: List texts in group folder description: "Return plagiarism text checks in a group folder." parameters: - $ref: '#/components/parameters/IdPath' - $ref: '#/components/parameters/FolderIdPath' - $ref: '#/components/parameters/PageQuery' - $ref: '#/components/parameters/SizeQuery' responses: '200': $ref: '#/components/responses/SuccessWithTextsList' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/groups/documents/{id}/folders/{folderId}/: get: operationId: listGroupFolderDocuments tags: - Folders summary: List documents in group folder description: "Return plagiarism and AI check documents in a group folder." parameters: - $ref: '#/components/parameters/IdPath' - $ref: '#/components/parameters/FolderIdPath' - $ref: '#/components/parameters/PageQuery' - $ref: '#/components/parameters/SizeQuery' responses: '200': $ref: '#/components/responses/SuccessWithTextDatas' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/agreement/create/{type}/{version}/: post: operationId: acceptAgreement tags: - Agreements summary: Accept agreement description: "Store that the authenticated user accepted a specific agreement type and version." parameters: - $ref: '#/components/parameters/AgreementTypePath' - $ref: '#/components/parameters/AgreementVersionPath' responses: '201': $ref: '#/components/responses/GenericCreated' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/agreement/view/{type}/{version}/: get: operationId: getAgreement tags: - Agreements summary: Get accepted agreement description: "Return information about the authenticated user's accepted agreement for a type and version." parameters: - $ref: '#/components/parameters/AgreementTypePath' - $ref: '#/components/parameters/AgreementVersionPath' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/agreement/list/: get: operationId: listAgreements tags: - Agreements summary: List accepted agreements description: "Return accepted agreements for the authenticated user." responses: '200': $ref: '#/components/responses/GenericDataResponse' '403': $ref: '#/components/responses/Forbidden' /api/v1/payment-link-info/{hash}/: get: operationId: getPaymentLinkInfo tags: - Subscriptions summary: Get payment link information description: "Return public information for a payment link identified by hash." parameters: - $ref: '#/components/parameters/HashPath' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '404': $ref: '#/components/responses/NotFound' /api/v1/google-classroom/subscriptions/: get: operationId: listGoogleClassroomSubscriptions tags: - Integrations summary: List Google Classroom subscriptions description: "Return Google Classroom courses or subscription state for the authenticated user." responses: '200': $ref: '#/components/responses/GenericDataResponse' '403': $ref: '#/components/responses/Forbidden' /api/v1/google-classroom/subscribe/{course}/: post: operationId: subscribeGoogleClassroomCourse tags: - Integrations summary: Subscribe Google Classroom course description: "Subscribe the authenticated user to a Google Classroom course integration." parameters: - $ref: '#/components/parameters/CoursePath' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/google-classroom/unsubscribe/{course}/: post: operationId: unsubscribeGoogleClassroomCourse tags: - Integrations summary: Unsubscribe Google Classroom course description: "Unsubscribe the authenticated user from a Google Classroom course integration." parameters: - $ref: '#/components/parameters/CoursePath' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/search-settings/: get: operationId: listSearchSettings tags: - Search Settings summary: Get search settings description: "Return search settings for the authenticated user." responses: '200': $ref: '#/components/responses/GenericDataResponse' '403': $ref: '#/components/responses/Forbidden' post: operationId: saveSearchSettings tags: - Search Settings summary: Save search settings description: "Save search settings for the authenticated user, such as source minimum percentage." requestBody: $ref: '#/components/requestBodies/SearchSettingsRequest' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/user-review/{type}/: get: operationId: getUserReview tags: - User summary: Get user review description: "Return the authenticated user's review for the requested review type." parameters: - $ref: '#/components/parameters/UserReviewTypePath' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/user-review/: post: operationId: setUserReview tags: - User summary: Save user review description: "Save review feedback for the authenticated user. The request includes a review type and may include score, comment, and text ID." requestBody: $ref: '#/components/requestBodies/UserReviewRequest' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/grammar-check/is-active/{id}/: post: operationId: isGrammarCheckActive tags: - Grammar Check summary: Check grammar-check activation description: "Return whether grammar checking is active for a text or account context." parameters: - $ref: '#/components/parameters/IdPath' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/grammar-check/activate/{id}/: post: operationId: activateGrammarCheck tags: - Grammar Check summary: Activate grammar check description: "Activate grammar checking for a text or account context." parameters: - $ref: '#/components/parameters/IdPath' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/grammar-check/check/{id}/: post: operationId: createGrammarCheck tags: - Grammar Check summary: Run grammar check description: "Send text content for grammar checking and return grammar matches when available." parameters: - $ref: '#/components/parameters/IdPath' requestBody: $ref: '#/components/requestBodies/GenericFormRequest' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/grammar-check/report/{id}/: post: operationId: getGrammarCheckReport tags: - Grammar Check summary: Get grammar-check report description: "Return a grammar-check report for a text visible to the authenticated user." parameters: - $ref: '#/components/parameters/IdPath' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/grammar-check/independed-check/: post: operationId: createIndependentGrammarCheck tags: - Grammar Check summary: Run independent grammar check description: "Create a grammar check that is independent of an existing text record." requestBody: $ref: '#/components/requestBodies/GenericFormRequest' responses: '201': $ref: '#/components/responses/GenericCreated' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/grammar-check/independed-check/{id}/: get: operationId: getIndependentGrammarCheckReport tags: - Grammar Check summary: Get independent grammar-check report description: "Return an independent grammar-check report by ID." parameters: - $ref: '#/components/parameters/IdPath' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/subscriptions/: get: operationId: listUserSubscriptions tags: - Subscriptions summary: List user subscriptions description: "Return subscription details for the authenticated user." responses: '200': $ref: '#/components/responses/GenericDataResponse' '403': $ref: '#/components/responses/Forbidden' /api/v1/subscriptions/{id}/: delete: operationId: cancelSubscription tags: - Subscriptions summary: Cancel subscription description: "Cancel a subscription visible to the authenticated user." parameters: - $ref: '#/components/parameters/IdPath' responses: '200': $ref: '#/components/responses/SuccessOnly' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/lti-tool-deployment/: get: operationId: listLtiToolDeployments tags: - LTI Tool Deployment summary: List LTI tool deployments description: "Return LTI tool deployments visible to the authenticated user." responses: '200': $ref: '#/components/responses/GenericDataResponse' '403': $ref: '#/components/responses/Forbidden' /api/v1/lti-tool-deployment/create-manual/: post: operationId: createManualLtiToolDeployment tags: - LTI Tool Deployment summary: Create manual LTI tool deployment description: "Register an LMS platform manually by sending issuer, client, deployment, JWKS, token, and authorization URLs." requestBody: $ref: '#/components/requestBodies/LtiToolDeploymentManualRequest' responses: '201': $ref: '#/components/responses/GenericCreated' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/lti-tool-deployment/create-dynamic-url/: post: operationId: createDynamicLtiToolDeployment tags: - LTI Tool Deployment summary: Create dynamic LTI tool deployment URL description: "Create dynamic-registration data for an LTI tool deployment." requestBody: $ref: '#/components/requestBodies/LtiToolDeploymentDynamicRequest' responses: '201': $ref: '#/components/responses/GenericCreated' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/tool/essay-grader/: post: operationId: authorizeEssayGrader tags: - Tools summary: Authorize essay grader description: "Return authorization state or launch data for the AI essay grader tool." requestBody: $ref: '#/components/requestBodies/GenericFormRequest' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/rubric/{id}/: parameters: - $ref: '#/components/parameters/IdPath' get: operationId: getRubric tags: - Rubrics summary: Get rubric description: "Return rubric configuration and grading result for a text visible to the authenticated user." responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' post: operationId: saveRubricGrade tags: - Rubrics summary: Save rubric grade description: "Save rubric grading selections for a text. Teachers and owners can grade texts in eligible group accounts." requestBody: $ref: '#/components/requestBodies/RubricGradeRequest' responses: '201': $ref: '#/components/responses/GenericCreated' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/submission-grade/{id}/: parameters: - $ref: '#/components/parameters/IdPath' get: operationId: getSubmissionGrade tags: - Submission Grades summary: Get submission grade description: "Return custom grade data for a submission." responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' post: operationId: saveSubmissionGrade tags: - Submission Grades summary: Save submission grade description: "Save a custom grade from 0 to 100 for a submission." requestBody: $ref: '#/components/requestBodies/SubmissionGradeRequest' responses: '200': $ref: '#/components/responses/GenericDataResponse' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' /api/v1/user/verify-email/: post: operationId: verifyUserEmail tags: - User summary: Verify user email description: "Verify the authenticated user's email address using a submitted verification code." requestBody: $ref: '#/components/requestBodies/UserVerifyEmailRequest' responses: '200': $ref: '#/components/responses/SuccessOnly' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' /api/v1/user/send-verify-email/: post: operationId: sendUserVerifyEmail tags: - User summary: Send verification email description: "Send an email-verification code to the authenticated user." responses: '200': $ref: '#/components/responses/SuccessOnly' '400': $ref: '#/components/responses/BadRequest' '403': $ref: '#/components/responses/Forbidden' components: securitySchemes: ApiTokenHeader: type: apiKey in: header name: X-API-TOKEN description: User API token for authenticated `/api/v1` and `/api/v2` requests. Organization endpoints under `/api/org` use `group_token` in the request body instead. requestBodies: ExtensionReportWriteRequest: required: true content: application/x-www-form-urlencoded: schema: type: object required: - text_id properties: text_id: type: integer description: ID of the text this report belongs to. Must be owned by the authenticated user. example: 345 item_id: type: string maxLength: 512 nullable: true description: "External item identifier. Must be unique among records owned by the authenticated user. Empty string is stored as `null`; `null` is allowed multiple times per user." example: john-course1-quiz5-question9 plagiarism: type: number format: float nullable: true description: Plagiarism percentage (0–100). Omit or pass an empty string to store `null`. example: 25.5 plagiarism_error: type: string nullable: true description: Error message from the plagiarism check. Omit or pass an empty string to store `null`. example: null ai: type: number format: float nullable: true description: AI-detection score (0–100). Omit or pass an empty string to store `null`. example: 10.25 ai_error: type: string nullable: true description: Error message from the AI check. Omit or pass an empty string to store `null`. example: null checking: type: boolean description: Whether the record is currently being checked. Defaults to `false`. example: false ExtensionReportBatchUpsertRequest: required: true content: application/json: schema: type: array items: type: object required: - text_id properties: id: type: integer nullable: true description: "Existing report ID. When present, the record with this id is looked up and updated (`item_id` in the body is written as the new value but is not used for lookup). Pass only `id` or `item_id` when an update is needed." example: 12 item_id: type: string maxLength: 512 nullable: true description: "External item identifier. When `id` is absent, used as the upsert lookup key for records owned by the current user: matches update an existing record, misses create a new record with this `item_id`. Must be unique among records owned by the authenticated user; `null` is allowed multiple times per user." example: john-course1-quiz5-question9 text_id: type: integer description: ID of the text this report belongs to. Must be owned by the authenticated user. example: 345 plagiarism: type: number format: float nullable: true description: Plagiarism percentage (0–100). Omit or pass `null` to store `null`. example: 25.5 plagiarism_error: type: string nullable: true description: Error message from the plagiarism check. Omit or pass `null` to store `null`. example: null ai: type: number format: float nullable: true description: AI-detection score (0–100). Omit or pass `null` to store `null`. example: 10.25 ai_error: type: string nullable: true description: Error message from the AI check. Omit or pass `null` to store `null`. example: null checking: type: boolean description: Whether the record is currently being checked. Defaults to `false`. example: false example: - text_id: 345 item_id: john-course1-quiz5-question9 plagiarism: 25.5 plagiarism_error: null ai: 10.25 ai_error: null checking: false OneRosterSyncSetupRequest: required: true content: application/x-www-form-urlencoded: schema: type: object required: - url properties: url: type: string description: "FTP or FTPS URL of the directory that contains `enrollments.csv` and `users.csv`. Must include credentials if the server requires authentication. Maximum length: 80 characters." example: "ftps://user:password@ftp.example.com/oneroster/" enabled: type: boolean description: "Whether sync is enabled. When `false` the record is saved with status `2` (disabled) and the connection is not tested. Defaults to `true`." example: true GenericFormRequest: required: false content: application/x-www-form-urlencoded: schema: type: object additionalProperties: true description: Endpoint-specific form fields handled by the controller. multipart/form-data: schema: type: object additionalProperties: true description: Endpoint-specific multipart fields handled by the controller. GenericJsonRequest: required: false content: application/json: schema: type: object additionalProperties: true description: Endpoint-specific JSON payload handled by the controller. application/x-www-form-urlencoded: schema: type: object additionalProperties: true description: Endpoint-specific form fields handled by the controller. FolderCreateRequest: required: true content: application/x-www-form-urlencoded: schema: type: object required: - groupId - name properties: groupId: type: integer description: Group ID that will own the folder. example: 5 name: type: string description: Folder name. example: "My folder" description: type: string description: Optional folder description. example: "Research papers" parent: type: integer nullable: true description: Optional parent folder ID. example: 10 FolderUpdateRequest: required: false content: application/x-www-form-urlencoded: schema: type: object properties: name: type: string description: Updated folder name. description: type: string description: Updated folder description. parent: type: integer nullable: true description: Updated parent folder ID. GroupCreateRequest: required: true content: application/x-www-form-urlencoded: schema: type: object required: - name properties: name: type: string description: Group display name. example: "Test Group" SearchSettingsRequest: required: true content: application/x-www-form-urlencoded: schema: type: object properties: source_min_percent: type: integer description: Minimum source percentage to keep in report search settings. example: 30 UserReviewRequest: required: true content: application/x-www-form-urlencoded: schema: type: object required: - type properties: type: type: integer description: Review type. example: 1 comment: type: string nullable: true description: Optional review comment. example: "Helpful result" score: type: integer nullable: true description: Optional review score. example: 5 text_id: type: integer nullable: true description: Optional text ID related to the review. example: 15 LtiToolDeploymentManualRequest: required: true content: application/x-www-form-urlencoded: schema: type: object required: - group_id - issuer - client_id - deployment_id - jwks_url - token_url - auth_url properties: group_id: type: integer description: Group ID for the deployment. example: 1459 lms: type: string enum: [moodle, canvas, brightspace, schoology, custom] default: custom description: LMS the deployment targets. Defaults to `custom` when omitted. example: "moodle" issuer: type: string description: LMS platform issuer. example: "http://moodle.local" client_id: type: string description: Platform client ID. example: "Csu0vTspnhGxZD3" deployment_id: type: string description: LMS deployment ID. example: "31" jwks_url: type: string format: uri description: Platform JWKS URL. example: "http://moodle.local/mod/lti/certs.php" token_url: type: string format: uri description: Platform token URL. example: "http://moodle.local/mod/lti/token.php" auth_url: type: string format: uri description: Platform authorization URL. example: "http://moodle.local/mod/lti/auth.php" LtiToolDeploymentDynamicRequest: required: true content: application/x-www-form-urlencoded: schema: type: object required: - group_id properties: group_id: type: integer description: Group ID for the deployment. example: 1459 lms: type: string enum: [moodle, canvas, brightspace, schoology, custom] default: custom description: LMS the deployment targets. Defaults to `custom` when omitted. example: "moodle" RubricGradeRequest: required: true content: application/x-www-form-urlencoded: schema: type: object required: - grade properties: grade: type: object additionalProperties: true description: Nested rubric criteria/rating selections, for example `grade[rubric_id][criteria_id]=rating_id`. SubmissionGradeRequest: required: true content: application/x-www-form-urlencoded: schema: type: object required: - grade properties: grade: type: integer minimum: 0 maximum: 100 description: Submission grade from 0 to 100. example: 40 UserVerifyEmailRequest: required: true content: application/x-www-form-urlencoded: schema: type: object required: - code properties: code: type: string description: Verification code sent to the user. example: "123456" TextCreateRequest: required: true content: application/x-www-form-urlencoded: schema: type: object required: - text properties: text: type: string minLength: 80 description: Text content to check. language: type: string example: en validation_hash: type: string callback: type: string format: uri filename: type: string exclude: type: string description: JSON array of text IDs to exclude. example: "[1,2]" exclude_groups: type: string description: JSON array of group IDs to exclude. example: "[3,4]" group_id: type: integer description: Optional group ID to charge and associate with the check. The authenticated user must belong to the group. custom_author: type: string description: Custom author display name. Required for group teachers and owners when the group has custom-author enforcement enabled. skip_english_words_validation: type: boolean default: false description: Skip English-word validation. Groups with language validation disabled can force this behavior. skip_percentage_words_validation: type: boolean default: false description: Skip letter-percentage validation. Groups with language validation disabled can force this behavior. integration_course: type: string integration_course_work: type: string integration_submission: type: string integration_attachment: type: string multipart/form-data: schema: type: object required: - text properties: text: type: string format: binary description: File to check. language: type: string example: en callback: type: string format: uri filename: type: string group_id: type: integer description: Optional group ID to charge and associate with the check. The authenticated user must belong to the group. FormattedTextCreateRequest: description: | Submit either a plain-text `text` form field or an uploaded file in the multipart `text` field. The create endpoint uses only formatted-text fields documented here. required: true content: application/x-www-form-urlencoded: schema: type: object required: - text properties: text: type: string minLength: 80 description: Plain text content to parse, store, and submit for a formatted plagiarism check. example: | A clear API contract helps developers submit documents, monitor check status, and retrieve structured plagiarism reports without relying on UI-only workflows. group_id: type: integer description: Optional group ID to charge and associate with the check. The authenticated user must belong to the group. example: 100 custom_author: type: string description: Optional custom author display name saved with the text. example: "Student Name" multipart/form-data: schema: type: object required: - text properties: text: type: string format: binary description: Uploaded file to parse, store, and submit for a formatted plagiarism check. filename: type: string description: Optional filename fallback. Uploaded file submissions normally use the original uploaded file name. example: formatted-submission.pdf group_id: type: integer description: Optional group ID to charge and associate with the check. The authenticated user must belong to the group. example: 100 custom_author: type: string description: Optional custom author display name saved with the text. example: "Student Name" FormattedTextValidateRequest: description: | Submit either a plain-text `text` form field or an uploaded file in the multipart `text` field. Validation returns counts and warnings but does not create a check or charge balance. required: true content: application/x-www-form-urlencoded: schema: type: object required: - text properties: text: type: string minLength: 80 maxLength: 1048576 description: Plain text content to parse and validate. example: | Some valid text with enough words and characters to pass the formatted text validation step before a user submits the final plagiarism check. filename: type: string description: Optional filename to use while processing the submitted text. example: draft.txt group_id: type: integer description: Optional group ID. If the group disables language validation, related validation checks are skipped. example: 100 custom_author: type: string description: Optional custom author display name used during validation. example: "Student Name" skip_english_words_validation: type: boolean default: false description: Skip the English-word percentage validation when allowed by the validation service. skip_percentage_words_validation: type: boolean default: false description: Skip the letter-percentage validation when allowed by the validation service. multipart/form-data: schema: type: object required: - text properties: text: type: string format: binary description: Uploaded file to parse and validate. filename: type: string description: Optional filename fallback. Uploaded file submissions normally use the original uploaded file name. example: draft.pdf group_id: type: integer description: Optional group ID. If the group disables language validation, related validation checks are skipped. example: 100 custom_author: type: string description: Optional custom author display name used during validation. example: "Student Name" skip_english_words_validation: type: boolean default: false description: Skip the English-word percentage validation when allowed by the validation service. skip_percentage_words_validation: type: boolean default: false description: Skip the letter-percentage validation when allowed by the validation service. TextsDeleteRequest: required: true content: application/x-www-form-urlencoded: schema: type: object required: - id properties: id: type: array minItems: 1 items: type: integer minimum: 1 description: Text IDs to delete. Symfony receives this as `id[]`. example: [1, 3] encoding: id: style: form explode: true AiCheckCreateRequest: description: | Submit either `text` or `file`. The endpoint strips the submitted content, requires the configured minimum character length, and enforces AI package and free/paid word-limit rules unless `skip_orders_validation` is true. required: true content: application/x-www-form-urlencoded: schema: type: object properties: text: type: string minLength: 80 description: Text content to check for AI-generated writing. group_id: type: integer description: Optional group ID for a group AI check. The authenticated user must belong to the group. force_language: type: string description: Optional language code to store for the AI check instead of auto-detection. skip_orders_validation: type: boolean default: false description: Skip AI package and free/paid word-limit validation. Intended for trusted internal flows. encoding: skip_orders_validation: style: form multipart/form-data: schema: type: object properties: file: type: string format: binary description: File to parse and check for AI-generated writing. group_id: type: integer description: Optional group ID for a group AI check. The authenticated user must belong to the group. force_language: type: string description: Optional language code to store for the AI check instead of auto-detection. skip_orders_validation: type: boolean default: false description: Skip AI package and free/paid word-limit validation. Intended for trusted internal flows. AiCheckMarkRequest: required: true content: application/x-www-form-urlencoded: schema: type: object required: - mark properties: mark: type: integer description: 1 for like, 0 for dislike. enum: [0, 1] comment: type: string description: Optional comment saved with the user's AI result feedback. OrgTextCheckRequest: required: true content: application/x-www-form-urlencoded: schema: type: object required: - group_token - author - text properties: group_token: type: string example: "G-HEfFiCHYWYx...." description: Organization group token. It must start with `G-` and identify an active group. author: type: string format: email example: "student@example.com" description: Email address of the group member who owns the submitted check. text: type: string minLength: 80 description: Text content to check. example: | An application programming interface is a set of definitions and protocols for building and integrating application software. A clear API makes it easier for developers to connect software components and automate repeatable workflows. filename: type: string example: submission.txt description: Optional filename to store with the text check. custom_author: type: string example: "Student Name" description: Optional display name for the author in group reports. callback: type: string format: uri example: "https://example.com/plagcheck/callback" description: Optional callback URL called after processing finishes. multipart/form-data: schema: type: object required: - group_token - author - text properties: group_token: type: string example: "G-HEfFiCHYWYx...." description: Organization group token. It must start with `G-` and identify an active group. author: type: string format: email example: "student@example.com" description: Email address of the group member who owns the submitted check. text: type: string format: binary description: File to check. The implementation reads uploaded files from the `text` field. filename: type: string example: submission.docx description: Optional filename override. If omitted, the uploaded file name is used. custom_author: type: string example: "Student Name" description: Optional display name for the author in group reports. callback: type: string format: uri example: "https://example.com/plagcheck/callback" description: Optional callback URL called after processing finishes. OrgTokenRequest: required: true content: application/x-www-form-urlencoded: schema: type: object required: - group_token properties: group_token: type: string example: "G-HEfFiCHYWYx...." description: Organization group token. It must start with `G-` and identify the group that owns the text. OrgHasMemberRequest: required: true content: application/x-www-form-urlencoded: schema: type: object required: - group_token - email properties: group_token: type: string example: "G-HEfFiCHYWYx...." description: Organization group token. It must start with `G-` and identify an active group. email: type: string format: email example: "student@example.com" description: Email address to look up in the group membership list. OrgAutoRegistrationRequest: required: true content: application/x-www-form-urlencoded: schema: type: object required: - group_token - email - role properties: group_token: type: string example: "G-HEfFiCHYWYx...." description: Organization group token. It must start with `G-` and identify the group receiving the member. email: type: string format: email example: "student@example.com" description: Email address for the member to create or add. name: type: string example: "Student Name" description: Optional display name for a newly created user. role: type: integer enum: [2, 3] example: 3 description: Member role to create. `2` is teacher and `3` is student; owner role is not allowed. GroupMemberCreateRequest: required: true content: application/x-www-form-urlencoded: schema: type: object required: - email - role properties: email: type: string format: email example: "student@example.com" description: Email address for the member to add. If the user does not exist, the API creates one. role: type: string enum: [teacher, student] example: student description: Group role for the new member. name: type: string example: "Student Name" description: Optional display name used when a new user is created. limit: type: integer nullable: true example: 100 description: Optional page limit for the member. `0` blocks checks for the member; omit the field for no explicit member limit. GroupMemberUpdateRequest: required: false content: application/x-www-form-urlencoded: schema: type: object properties: role: type: string enum: [teacher, student] example: teacher description: New group role. If omitted, the current implementation treats the value as `student`. limit: oneOf: - type: integer nullable: true - type: string enum: ["no limit"] example: "no limit" description: New page limit for the member. Send `no limit` to clear the limit; omit the field to keep the current limit. responses: ExtensionReportResponse: description: A single Integrito report-data record. content: application/json: schema: type: object properties: success: type: boolean example: true data: type: object properties: report: $ref: '#/components/schemas/IntegritoReportData' example: success: true data: report: id: "12" text_id: "345" plagiarism: 25.5 plagiarism_error: null ai: 10.25 ai_error: null checking: false created_at: "1706199949000" updated_at: null ExtensionReportListResponse: description: A paginated list of Integrito report-data records. content: application/json: schema: type: object properties: success: type: boolean example: true data: type: object properties: reports: type: array items: $ref: '#/components/schemas/IntegritoReportData' pagination: type: object description: Standard pagination envelope. properties: currentPage: type: integer example: 1 numItemsPerPage: type: integer example: 30 totalCount: type: integer example: 1 ExtensionReportBatchResponse: description: The result of a batch create-or-update operation. content: application/json: schema: type: object properties: success: type: boolean example: true data: type: object properties: reports: type: array items: $ref: '#/components/schemas/IntegritoReportData' example: success: true data: reports: - id: "12" text_id: "345" plagiarism: 25.5 plagiarism_error: null ai: 10.25 ai_error: null checking: false created_at: "1706199949000" updated_at: null BadRequest: description: The request is invalid. Check required fields, field formats, and resource ownership. content: application/json: schema: anyOf: - $ref: '#/components/schemas/ValidationError' - $ref: '#/components/schemas/Error' examples: missingParameter: value: success: false message: "Parameter email is required" validationMessages: value: success: false messages: - "Maximum amount of members has been reached" Conflict: description: The request conflicts with account or group business rules, such as exhausted balance or member limits. content: application/json: schema: $ref: '#/components/schemas/BusinessRuleError' RateLimited: description: The request was rejected because another submission is already in progress or the same text was submitted too recently. content: application/json: schema: $ref: '#/components/schemas/BusinessRuleError' OneRosterSyncDataResponse: description: The request succeeded and returned the OneRoster sync configuration for the group. content: application/json: schema: type: object properties: success: type: boolean example: true data: $ref: '#/components/schemas/OneRosterSyncData' example: success: true data: id: 7 status: 3 url: "ftps://user:password@ftp.example.com/oneroster/" last_synced_at: 1716800000 message: null GenericDataResponse: description: The request succeeded and returned endpoint-specific data. content: application/json: schema: $ref: '#/components/schemas/GenericSuccessResponse' GenericCreated: description: The resource was created successfully. content: application/json: schema: $ref: '#/components/schemas/GenericSuccessResponse' TextCreated: description: The plagiarism check was created successfully and billing information was returned. content: application/json: schema: type: object properties: success: type: boolean example: true data: type: object properties: text: $ref: '#/components/schemas/Text' charged: type: integer example: 1 description: Number of regular pages charged for the check. bonus_charged: type: integer example: 0 description: Number of bonus pages charged for the check. groupId: type: integer nullable: true example: null description: Group ID charged for the check, or `null` for an individual check. example: success: true data: text: id: 15 filename: example.pdf created_at: 1516279363000 updated_at: 1516279364000 submitted_at: 1516279364000 state: 3 language: en pages: 1 words: 177 charged: 1 bonus_charged: 0 groupId: null FormattedTextCreated: description: The formatted text check was created successfully and billing information was returned. content: application/json: schema: type: object properties: success: type: boolean example: true data: type: object properties: text: $ref: '#/components/schemas/Text' charged: type: integer example: 1 description: Number of regular pages charged for the formatted check. bonus_charged: type: integer example: 0 description: Number of bonus pages charged for the formatted check. example: success: true data: text: id: 15 filename: sample.pdf version: 1 created_at: 1516279363000 updated_at: 1516279364000 submitted_at: 1516279364000 state: 3 language: en pages: 1 words: 177 charged: 1 bonus_charged: 0 SuccessWithOrgText: description: The organization text check was created successfully. content: application/json: schema: type: object properties: success: type: boolean example: true data: $ref: '#/components/schemas/Text' SuccessWithTextData: description: The request succeeded and returned a text check object. content: application/json: schema: type: object properties: data: $ref: '#/components/schemas/Text' SuccessWithFormattedTextValidation: description: The formatted text is valid enough to submit for checking. content: application/json: schema: $ref: '#/components/schemas/FormattedTextValidation' example: success: true warning: "" words: 18 pages: 1 SubmissionFailed: description: | The submission was rejected. The message is safe to display to an end user; internal detail is logged, not returned. content: application/json: schema: anyOf: - $ref: '#/components/schemas/SubmissionError' - $ref: '#/components/schemas/Error' examples: conversionFailed: value: success: false code: file_conversion_failed message: "We could not convert this document for checking. Please re-save it as PDF or DOCX and upload it again." unsupportedType: value: success: false code: unsupported_extension message: "This file type is not supported. Supported types: doc, docx, odp, odt, pdf, ppt, pptx, rtf, txt." alreadyInProgress: value: success: false code: text_already_in_progress message: "Text is already in progress" missingText: value: success: false message: "text is required" FormattedTextValidationFailed: description: | The formatted text could not be validated. Some validation failures include `code`, `words`, and `pages`; request parsing errors use the common error shape. content: application/json: schema: anyOf: - $ref: '#/components/schemas/FormattedTextValidationError' - $ref: '#/components/schemas/Error' examples: validation: value: success: false code: 1 message: "Text is shorter than 80 characters" words: 3 pages: 1 tooLong: value: success: false code: 5 message: "The text is too long. Maximum number of symbols - 1048576" words: 152341 pages: 554 missingText: value: success: false message: "text is required" SuccessWithFormattedMarkup: description: The request succeeded and returned stored formatted markup assets. content: application/json: schema: type: object properties: success: type: boolean example: true data: $ref: '#/components/schemas/FormattedMarkup' example: success: true data: html: "
Example text
" map: success: true text: "Example text" SuccessWithTextDatas: description: The request succeeded and returned a paginated list of plagiarism and AI check documents. content: application/json: schema: type: object properties: success: type: boolean example: true data: type: object properties: documents: type: array items: oneOf: - $ref: '#/components/schemas/Text' - $ref: '#/components/schemas/AiCheck' pagination: $ref: '#/components/schemas/Pagination' SuccessWithTextsList: description: The request succeeded and returned a paginated list of text checks. content: application/json: schema: type: object properties: data: type: object properties: texts: type: array items: $ref: '#/components/schemas/Text' pagination: $ref: '#/components/schemas/Pagination' SuccessWithTextDataAndSuccess: description: The request succeeded and returned the current check status. content: application/json: schema: type: object properties: success: type: boolean example: true data: $ref: '#/components/schemas/Text' SuccessWithReportData: description: | The request succeeded and returned report metadata and parsed report data. Some successful responses include a `warning` and `report_data: null` when parsed data is unavailable. content: application/json: schema: type: object properties: success: type: boolean example: true description: Present on text-report responses; can be `false` when the text is not checked or parsed data is missing. data: type: object properties: report: type: object allOf: - $ref: '#/components/schemas/Report' nullable: true report_data: type: object allOf: - $ref: '#/components/schemas/ReportData' nullable: true warning: type: string example: "Report data is missed or its parsing failed" description: Warning message included when report data cannot be returned. SuccessWithReportDataAndSuccess: description: The request succeeded and returned report metadata and parsed report data. content: application/json: schema: type: object properties: success: type: boolean example: true data: type: object properties: report: type: object allOf: - $ref: '#/components/schemas/Report' nullable: true report_data: type: object allOf: - $ref: '#/components/schemas/ReportData' nullable: true SuccessOnly: description: The request succeeded. content: application/json: schema: type: object properties: success: type: boolean example: true SuccessWithHasMember: description: Indicates whether the email belongs to the group and whether auto-registration is enabled. content: application/json: schema: type: object properties: success: type: boolean example: true has_member: type: boolean example: true is_auto_registration_enabled: type: boolean example: true SuccessWithMemberId: description: The request succeeded and returned the created member ID. content: application/json: schema: type: object properties: success: type: boolean example: true member_id: type: integer example: 100500 SuccessWithAiCheck: description: The AI detection check was created successfully. content: application/json: schema: type: object properties: success: type: boolean example: true data: $ref: '#/components/schemas/AiCheck' SuccessWithAiCheckValidation: description: The AI detection check request is valid enough to submit for checking. content: application/json: schema: $ref: '#/components/schemas/AiCheckValidation' example: success: true data: words: 177 pages: 1 SuccessWithAiCheckResult: description: The request succeeded and returned the AI detection result. content: application/json: schema: type: object properties: success: type: boolean example: true data: $ref: '#/components/schemas/AiCheck' AiFeedbackSaved: description: The AI detection feedback was saved. content: application/json: schema: type: object properties: success: type: boolean example: true GroupMemberRemoved: description: The group member was removed. content: application/json: schema: type: object properties: success: type: boolean example: true SuccessWithGroups: description: The request succeeded and returned the groups visible to the current user. content: application/json: schema: type: object properties: success: type: boolean example: true data: type: object properties: groups: type: array items: $ref: '#/components/schemas/Group' SuccessWithGroup: description: The request succeeded and returned group details. content: application/json: schema: type: object properties: success: type: boolean example: true data: $ref: '#/components/schemas/Group' SuccessWithTransactions: description: The request succeeded and returned paginated group balance transactions. content: application/json: schema: type: object properties: success: type: boolean example: true data: type: object properties: transactions: type: array items: $ref: '#/components/schemas/Transaction' pagination: $ref: '#/components/schemas/Pagination' SuccessWithMembers: description: The request succeeded and returned paginated group members. content: application/json: schema: type: object properties: success: type: boolean example: true data: type: object properties: members: type: array items: $ref: '#/components/schemas/Member' pagination: $ref: '#/components/schemas/Pagination' SuccessWithMember: description: The request succeeded and returned the group member. content: application/json: schema: type: object properties: success: type: boolean example: true data: $ref: '#/components/schemas/Member' Forbidden: description: Authentication or authorization failed because the token is missing, invalid, blocked, or not allowed to access the resource. content: application/json: schema: anyOf: - $ref: '#/components/schemas/AuthError' - $ref: '#/components/schemas/Error' example: message: "Forbidden" NotFound: description: The requested resource was not found. content: application/json: schema: $ref: '#/components/schemas/Error' example: message: "Not Found" SuccessWithGroupView: description: The request succeeded and returned group details. content: application/json: schema: type: object properties: success: type: boolean example: true data: type: object required: - "id" - "name" - "created_at" - "owner" - "group_balance" properties: id: type: integer example: 100 description: Numeric group ID. name: type: string description: Group display name. example: "Test group" created_at: type: integer description: Group creation timestamp in milliseconds. example: 1512638171000 owner: type: object nullable: true description: Owner contact information, or `null` when no owner membership is found. properties: name: type: string example: John Doe description: Name of the group owner. email: type: string format: email example: example@example.com description: Email address of the group owner. group_balance: description: Current group balance details. $ref: '#/components/schemas/Account' parameters: IdPath: in: path name: id description: Numeric resource ID. required: true example: 15 schema: type: integer UserIdPath: in: path name: userId description: Numeric user ID. required: true example: 24 schema: type: integer LastTextIdPath: in: path name: lastTextId description: Cursor text ID. Use `0` to start from the beginning when supported. required: true example: 0 schema: type: integer minimum: 0 FolderIdPath: in: path name: folderId description: Numeric folder ID. required: true example: 10 schema: type: integer GroupIdUnderscorePath: in: path name: group_id description: Numeric group ID. required: true example: 100 schema: type: integer RoleIdPath: in: path name: role_id description: Numeric group role ID. required: true example: 3 schema: type: integer enum: [2, 3] AgreementTypePath: in: path name: type description: Agreement type identifier. required: true example: "terms" schema: type: string AgreementVersionPath: in: path name: version description: Agreement version identifier. required: true example: "1.0" schema: type: string HashPath: in: path name: hash description: Payment link hash. required: true example: "abc123" schema: type: string CoursePath: in: path name: course description: External course identifier. required: true example: "course-123" schema: type: string UserReviewTypePath: in: path name: type description: Numeric review type. required: true example: 1 schema: type: integer TextIdPath: in: path name: id description: Numeric ID of a text check or AI check, depending on the endpoint. required: true example: 15 schema: type: integer TextCheckIdPath: in: path name: textId description: Numeric ID of a text check. required: true example: 15 schema: type: integer ReportIdPath: in: path name: reportId description: Numeric report ID. required: true example: 15 schema: type: integer GroupIdPath: in: path name: id description: Numeric group ID. required: true example: 100 schema: type: integer MemberIdPath: in: path name: id description: Numeric group member ID. required: true example: 100 schema: type: integer SearchQuery: in: query name: search description: Optional text search filter. Matching fields depend on the endpoint, for example filename, member name, email, or transaction text. required: false example: John Doe schema: type: string DocumentTypesQuery: in: query name: types description: Optional document type filter for the combined documents list. required: false example: text schema: type: string PageQuery: in: query name: page description: Page number for paginated endpoints. Defaults to `1` when omitted. required: false example: 1 schema: type: integer minimum: 1 SizeQuery: in: query name: size description: Number of records per page. Defaults to `30` when omitted. required: false example: 30 schema: type: integer minimum: 1 UserIdQuery: in: query name: userId description: Filter by user ID. required: false example: 15 schema: type: integer FilterIdQuery: in: query name: filterId description: Filter by member ID or member role, depending on the endpoint. required: false example: 15 schema: type: integer GroupIdQuery: in: query name: groupId description: Optional group ID filter. required: false example: 100 schema: type: integer schemas: IntegritoReportData: type: object description: A single Integrito report-data record as returned by the API. properties: id: type: string nullable: true example: "12" description: Numeric report ID serialised as a string. text_id: type: string nullable: true example: "345" description: ID of the associated text, serialised as a string. item_id: type: string nullable: true maxLength: 512 example: john-course1-quiz5-question9 description: External item identifier set by the API consumer. Unique per owning user; `null` when no value was provided. plagiarism: type: number format: float nullable: true example: 25.5 description: Plagiarism percentage (0–100), or `null` when not yet checked. plagiarism_error: type: string nullable: true example: null description: Error message from the plagiarism check, or `null` when no error occurred. ai: type: number format: float nullable: true example: 10.25 description: AI-detection score (0–100), or `null` when not yet checked. ai_error: type: string nullable: true example: null description: Error message from the AI check, or `null` when no error occurred. checking: type: boolean example: false description: Whether the record is currently in a checking state. created_at: type: string nullable: true example: "1706199949000" description: Creation Unix timestamp in milliseconds, serialised as a string. updated_at: type: string nullable: true example: null description: Last-update Unix timestamp in milliseconds, serialised as a string. `null` until the record is updated. OneRosterSyncData: type: object description: OneRoster FTP sync configuration record for a group. properties: id: type: integer nullable: true example: 7 description: Record ID, or `null` when no configuration has been saved yet. status: type: integer nullable: true enum: [1, 2, 3] example: 3 description: | Sync status: - `1` — error (last sync or connection test failed; see `message` for details) - `2` — disabled - `3` — ok / enabled url: type: string nullable: true example: "ftps://user:password@ftp.example.com/oneroster/" description: Configured FTP/FTPS URL, or `null` when no configuration has been saved yet. last_synced_at: type: integer nullable: true example: 1716800000 description: Unix timestamp (seconds) of the last successful synchronisation, or `null` if the group has never been synced. message: type: string nullable: true example: null description: Error message from the last failed sync or connection test, or `null` when there is no error. GenericSuccessResponse: type: object description: Generic success envelope used for endpoints whose data shape is endpoint-specific. properties: success: type: boolean example: true data: description: Endpoint-specific response data. oneOf: - type: object nullable: true additionalProperties: true - type: array nullable: true items: type: object additionalProperties: true - type: string nullable: true - type: integer nullable: true - type: boolean nullable: true message: type: string nullable: true description: Optional informational message returned by some endpoints. FormattedTextValidation: type: object description: Result returned when formatted text validation succeeds. required: - success - warning - words - pages properties: success: type: boolean example: true warning: type: string nullable: true example: "" description: Optional validation warning. An empty string means no warning was produced. words: type: integer example: 18 description: Number of words parsed from the submitted text or file. pages: type: integer example: 1 description: Estimated page count calculated from the parsed word count. FormattedTextValidationError: type: object description: Validation failure returned after the formatted text was parsed. required: - success - message properties: success: type: boolean example: false code: type: integer nullable: true example: 1 description: Validation error code returned by the text validation service, when available. message: type: string example: "Text is shorter than 80 characters" description: Human-readable validation error message. words: type: integer example: 3 description: Parsed word count at the time validation failed, when available. pages: type: integer example: 1 description: Estimated page count at the time validation failed, when available. FormattedMarkup: type: object description: Stored formatted report assets for a formatted text. properties: html: type: string description: Rendered HTML markup generated for the formatted report. example: "Example text
" map: type: object additionalProperties: true description: Parsed JSON map generated by the formatted-text processor. example: success: true text: type: string description: Plain text stored for the formatted report. example: "Example text" Text: type: object description: Metadata for a submitted plagiarism check. required: - id - filename - created_at - updated_at - submitted_at - language - pages - words properties: id: type: integer example: 15 description: Numeric text check ID. version: type: integer nullable: true example: null description: Internal text/report format version, when available. user_id: type: integer example: 24 description: Creator user ID. Returned by create/status responses that do not embed the full creator object. filename: type: string example: example.pdf description: Original or generated file name for the submitted text. created_at: type: integer example: 1516279363000 description: Unix timestamp in milliseconds. updated_at: type: integer example: 1516279364000 description: Unix timestamp in milliseconds. submitted_at: type: integer nullable: true example: 1516279364000 description: Unix timestamp in milliseconds. is_deleted: type: boolean example: false description: Whether the text was marked as deleted. deleted_at: type: integer nullable: true example: null description: Deletion timestamp in milliseconds, or `null` when the text is active. state: type: integer enum: [2, 3, 4, 5] example: 3 description: | | ID | Name | Description | |---:|:-------|:------------| |2 | STATE_STORED | Text has been stored and is waiting to be submitted to the checking service. | |3 | STATE_SUBMITTED | Text has been submitted to the checking service and is being processed.| |4 | STATE_FAILED | Text has not been checked. An error happened.| |5 | STATE_CHECKED | Text has been successfully checked and you can receive the report.| language: type: string example: "en" description: Detected or submitted language code for the document. pages: type: integer example: 30 description: Estimated page count used for billing and limits. words: type: integer example: 127 description: Number of words detected in the submitted text. group_id: type: integer nullable: true example: 100 description: Group associated with the check, or `null` for an individual check. custom_author: type: string nullable: true example: "Student Name" description: Custom author display name saved for group checks. report_id: type: integer nullable: true example: 13 description: Report ID when the check has a plagiarism report. ai_report_id: type: integer nullable: true example: 15 description: AI report ID when an AI report is associated with this text. creator: allOf: - $ref: '#/components/schemas/User' description: User who created the text check. report: type: object nullable: true description: Plagiarism report summary, or `null` while the text is not checked. properties: id: type: integer example: 13 description: Numeric report ID. created_at: type: string example: "1643727471000" description: Report creation timestamp in milliseconds. source_count: type: integer example: 5 description: Number of matched sources in the report. percent: type: string example: "28.57" description: Similarity percentage for this report. ai_report: $ref: '#/components/schemas/AiCheck' integration_links: type: array description: Integration metadata for texts created through LMS or site integrations. Present only when integration links exist. items: type: object AiCheckValidation: type: object required: - success - data properties: success: type: boolean example: true data: type: object required: - words - pages properties: words: type: integer example: 177 description: Number of words parsed from the submitted text or file. pages: type: integer example: 1 description: Estimated AI check page count. One page is 275 words. Report: type: object required: - id - created_at - source_count - percent - text_id properties: id: type: integer example: 15 description: Numeric report ID. created_at: type: integer example: 1513617036000 description: Unix timestamp in milliseconds. source_count: type: integer example: 3 description: Number of matched sources found in the report. percent: oneOf: - type: number - type: string example: 97.60 description: Similarity percentage for the checked text. text_id: type: integer example: 55 description: Numeric ID of the text check associated with this report. group_id: type: integer nullable: true example: 100 description: Group associated with the text check, or `null`. ReportData: type: object description: Parsed plagiarism report data, including matched text fragments, sources, and similarity metrics. required: - version - length - created_at - nodes - indexes - references - header - quotes - sources - sources_count - matched_length - matched_percent - external_queries - destinations_clusters properties: version: type: string example: "1.1" description: Parsed report format version. length: type: integer example: 637 description: Total length of the checked text in characters. matched_length: type: integer example: 182 description: Total number of matched characters across all sources. matched_percent: type: number example: 28.57 description: Percentage of the submitted text matched to sources. nodes: type: array description: Text fragments with match metadata and references to sources. items: type: object properties: enabled: type: boolean example: true description: Whether this fragment is currently included in the similarity calculation. start: type: integer example: 0 description: Start character offset of the fragment. end: type: integer example: 19 description: End character offset of the fragment. text: type: string example: "lorem ipsum dolor" description: Text fragment content. sources: type: array items: type: integer description: Index of the source in the report `sources` array. example: 1 sources_improved: type: array items: type: integer example: 1 description: Index of the source in the report `sources` array. references: type: array items: type: integer example: 1 description: Index of a reference fragment in the report `references` array. headers: type: array items: type: integer example: 1 description: Index of a detected header fragment in the report `header` array. quotes: type: array items: type: integer example: 1 description: Index of a quoted fragment in the report `quotes` array. destinations_clusters: type: array items: type: integer example: 1 description: Index of a destination cluster related to this matched fragment. indexes: type: array description: Search indexes used to produce report matches. items: type: object properties: id: type: integer example: 0 description: Search index identifier. This also corresponds to the index position in the report `indexes` array. type: type: string example: "external" description: Search index type, for example external or checked. references: type: array description: Reference fragments detected in the submitted text. items: type: object properties: id: type: integer example: 0 description: Reference fragment ID. length: type: integer example: 35 description: Reference fragment length in characters. header: type: array description: Header fragments detected in the submitted text. items: type: object properties: id: type: integer example: 0 description: Header fragment ID. length: type: integer example: 35 description: Header fragment length in characters. quotes: type: array description: Quoted fragments detected in the submitted text. items: type: object properties: id: type: integer example: 0 description: Quote fragment ID. length: type: integer example: 35 description: Quote fragment length in characters. sources: type: array description: Matched external or internal sources. items: type: object properties: dst_pos_success: type: boolean example: true description: Whether destination positions were resolved successfully for this source. content_type: type: string example: "text/plain" description: MIME content type returned for the matched source when available. index: type: integer example: 0 description: Index ID that produced this source match. source: type: string example: "https://en.wikipedia.org/wiki/Open_source" description: URL or source identifier for the matched source. length: type: integer example: 255 description: Length of the matched source text in characters. percent: type: number example: 40.03 description: Percentage contribution of this source to the overall similarity score. link: type: object description: Human-readable link metadata for the source. properties: name: type: string description: Display name for the source domain or document. url: type: array description: URLs associated with this source. items: type: string tf_idf: type: boolean example: false description: Whether TF-IDF matching was used for this source. plagiarism_length: type: integer example: 182 description: Number of matched characters attributed to this source. plagiarism_percent: type: number example: 28.57 description: Percentage of submitted text matched to this source. created_at: type: string example: "2017-05-12 05:10:57" description: Parsed report creation date. sources_count: type: integer example: 5 description: Total number of matched sources in the report. external_queries: type: integer example: 12 description: Number of external search queries used for the report. destinations_clusters: type: array description: Clusters linking matched source destinations to text offsets. items: type: object properties: source: type: integer example: 0 description: Source index for this destination cluster. id: type: integer example: 0 description: Destination cluster ID. offsets: type: array description: Matched offsets for this destination cluster. items: type: object properties: start: type: integer example: 20 description: Start character offset. end: type: integer example: 34 description: End character offset. cos: type: number example: 1 description: Cosine similarity score for the offset. ignored_ranges: type: array description: | Character ranges excluded from the similarity calculation because they match assignment ignore templates. This field is optional and is returned only when ignored ranges exist. items: $ref: '#/components/schemas/TextIgnoredRange' TextIgnoredRange: type: object description: A text range excluded from report similarity calculations. properties: id: type: integer nullable: true example: 123 description: Internal ignored range identifier. start: type: integer example: 42 description: Start character offset of the ignored range. end: type: integer example: 87 description: End character offset of the ignored range. filename: type: string example: "assignment-template.docx" description: Name of the ignore assignment template file that produced this range. ignore_assignment_template_id: type: integer nullable: true example: 55 description: Identifier of the ignore assignment template that produced this range. AiCheck: type: object description: AI-generated text detection report. properties: enabled: type: boolean example: true description: Whether AI detection is enabled for this report/user context. id: type: integer nullable: true example: 15 description: Numeric AI report ID, or `null` when a text has no AI report yet. status: type: integer nullable: true enum: [1, 2, 3, 4, 5, 7, 8, 9, 10] example: 3 description: | | ID | Name | Description | |---:|:-------|:------------| | 1 | STATUS_QUEUED | Check in queue | | 2 | STATUS_IN_PROGRESS | Check in progress | | 3 | STATUS_FAILED | Check failed | | 4 | STATUS_CHECKED | Successfully checked | | 5 | STATUS_NOT_ENOUGH_TEXT | Not enough text | | 7 | STATUS_NOT_ENOUGH_ORIGINAL_TEXT | Not enough text | | 8 | STATUS_TEXT_TOO_LONG | Text is too long| | 9 | STATUS_LANGUAGE_IS_NOT_SUPPORTED | Text language is not supported | | 10 | STATUS_CREATED | Check created | percent: type: number nullable: true example: 50.50 description: Overall probability that the submitted text was AI-generated. processed_percent: type: number nullable: true example: 70.25 description: Percentage of the submitted text classified as AI-generated. strong_percent: type: number nullable: true example: 40.25 description: Percentage of the submitted text classified as strongly likely to be AI-generated. likely_percent: type: number nullable: true example: 30.00 description: Percentage of the submitted text classified as likely to be AI-generated. mark: type: integer nullable: true enum: [0, 1] example: 1 description: "User feedback for the AI result: `1` means like, `0` means dislike, `null` means not rated." comment: type: string nullable: true example: "Lorem ipsum dolor" description: Optional user comment submitted with the AI result rating. comment_author: type: object nullable: true description: User who submitted the rating comment, or `null` when no feedback exists. properties: id: type: integer example: 24 description: Numeric user ID of the check author. name: type: string example: "John Doe" description: Display name of the check author. type: type: integer nullable: true example: 3 description: AI report type. For ChatGPT/perplexity checks this value is `3`. words: type: integer nullable: true example: 550 description: Word count calculated for the AI detection check. pages: type: integer nullable: true example: 2 description: Page count calculated for the AI detection check. parameters: type: object additionalProperties: type: string description: Detector parameters saved with the AI report, when present. group_id: type: integer nullable: true example: 100 description: Group ID associated with the AI check, or `null` for an individual check. creator: type: object allOf: - $ref: '#/components/schemas/User' nullable: true description: User who created the AI check, when included by the endpoint. has_own_content: type: boolean nullable: true description: Whether the report stores its own submitted content. conclusion_type: type: integer nullable: true description: Numeric conclusion category calculated for checked AI reports. conclusion: type: string nullable: true description: Human-readable conclusion calculated for checked AI reports. content: type: string nullable: true description: Original text content used for the AI detection check, when exposed by the endpoint. example: | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus molestie diam id lacus maximus, ac scelerisque neque suscipit. Pellentesque luctus elit cursus varius aliquam. Nam neque leo, cursus sit amet quam a, dignissim malesuada est. Sed efficitur finibus felis euismod mattis. Donec egestas nunc odio, vitae lacinia nunc pellentesque id. Etiam ornare nunc vel accumsan ullamcorper. Donec sed lacinia orci. chunks: type: array nullable: true description: Text ranges classified by the AI detector. items: type: object properties: reliability: type: integer example: 1 description: | | ID | Name | Description | |---:|:-------|:------------| | 1 | RELIABILITY_LIKELY | Sentence with a small reliability | | 2 | RELIABILITY_STRONG | Sentence with a big reliability | position: type: array items: type: integer example: [100, 200] description: Start and end character offsets for the AI-highlighted text fragment. ignored_ranges: type: array description: | Character ranges forced to "not AI generated" because they match assignment ignore templates. Chunks overlapping these ranges are trimmed, split, or removed before the AI percentages are calculated. The submitted text itself is never modified. items: $ref: '#/components/schemas/TextIgnoredRange' AuthError: type: object description: Authentication or authorization failure returned by Symfony/API access checks. required: - message properties: message: type: string example: "Forbidden" description: Human-readable authentication or authorization error. ValidationError: type: object description: Application-level validation error. properties: success: type: boolean example: false message: oneOf: - type: string - type: array items: type: string example: "Parameter email is required" description: Human-readable validation error, or a list of validation errors. messages: type: array items: type: string example: ["Maximum amount of members has been reached"] description: Alternate validation-message list used by some group member endpoints. code: type: integer nullable: true example: 1 description: Optional application-specific validation error code. data: type: string nullable: true description: Optional context value included by some validation errors. BusinessRuleError: type: object description: Business-rule error such as duplicate submission, exhausted balance, or member-limit failure. required: - message properties: success: type: boolean example: false message: type: string example: "Text is already in progress" description: Human-readable business-rule error. code: type: integer nullable: true example: 1 description: Optional application-specific error code. data: type: string nullable: true description: Optional context value included by some business-rule errors. Error: type: object description: | Error response shape used by the documented API endpoints. Some framework-level errors include only `message`; application-level validation and business-rule errors usually include `success: false`. properties: success: type: boolean example: false description: Always `false` for application-level errors that include this field. message: oneOf: - type: string - type: array items: type: string example: "Parameter email is required" description: Human-readable error message, or a list of validation messages for some endpoints. messages: type: array items: type: string example: ["Maximum amount of members has been reached"] description: Alternate validation-message list used by some group member endpoints. code: type: integer example: 1 description: Optional application-specific error code. data: type: string nullable: true description: Optional context value included by some business-rule errors. SubmissionError: type: object description: | Failure of a text submission or check creation. `message` is always safe to display to an end user: it never contains server paths, storage hosts, converter output or internal identifiers. Those details are written to the application log instead. `code` is stable and intended for clients that supply their own translations. See `docs/submission-error-messages.md`. required: - success - message properties: success: type: boolean example: false code: type: string description: Stable machine-readable reason. enum: - unsupported_extension - file_conversion_failed - file_unreadable - file_content_unsupported - file_corrupted - file_too_large - text_too_short - text_too_long - text_empty - text_not_utf8 - text_already_in_progress - text_validation_failed - not_enough_pages - not_enough_limits - not_group_member - group_disabled - user_disabled - service_unavailable - submission_failed example: file_conversion_failed message: type: string description: English wording safe to show to a teacher or student. example: "We could not convert this document for checking. Please re-save it as PDF or DOCX and upload it again." Account: type: object description: Balance counters for a user or group account. required: - balance - bonus - hold - hold_bonus - ai_balance properties: balance: description: Available balance in pages. One page is 275 words. type: integer example: 0 bonus: description: Available bonus balance in pages. One page is 275 words. type: integer example: 0 hold: description: Balance on hold. This field is deprecated. type: integer example: 0 hold_bonus: description: Bonus balance on hold. This field is deprecated. type: integer example: 0 ai_balance: description: Available AI-check balance. type: integer example: 0 Group: type: object description: Group or organization account visible to the current user. required: - "id" - "status" - "name" - "contact" - "additional_information" - "created_at" - "updated_at" - "group_balance" - "current_user_role" properties: id: type: integer example: 100 description: Numeric group ID. status: type: integer enum: [1, 2] example: 1 description: | | ID | Name | Description | |---:|:-------|------------:| | 1 | STATUS_ENABLED | Active group | | 2 | STATUS_DISABLED | Disabled group | name: type: string description: Group display name. example: "Test group" contact: type: string description: Contact information for the group or organization. example: "John Doe email