# Codequiry API — Full Reference (for developers and AI agents) > Source-code plagiarism, peer similarity, web/database matching, and AI-generated-code detection. Version: 1.0.0 | Base URL: `https://codequiry.com/api/v1` | Machine-readable spec: https://codequiry.com/openapi.json ## Authentication Every request requires the header `apikey: ` (a 64-character key from your Codequiry dashboard). There is no OAuth or Bearer token, and the key is **not** accepted as a query-string parameter or a body field — header only. A missing or malformed key returns HTTP 401. ## Rules an agent must follow These are the constraints that most often break generated integrations. Honour them before optimising anything else. 1. **Rate limit: 60 requests per minute, per client IP — not per API key.** Every endpoint shares one counter, and failed calls (including 401s) count against it. Multiple keys behind one server, NAT gateway, CI runner, or serverless region share the same budget. Over the limit you get `429` with a `Retry-After` header (seconds); wait that long, do not retry immediately. The limit is identical on every plan, so upgrading will not raise it. 2. **Never poll in a tight loop.** Analysis is asynchronous and typically takes minutes. Poll `POST /check/status` every 20-30 seconds. Polling once a second burns the entire minute's budget before the check has moved. 3. **Results are only available once the check completes.** `/check/overview`, `/check/results`, and `/check/export` return `409` while a check is still running. Treat `409` as "not ready yet, keep polling", not as a failure. 4. **Uploads must be ZIP archives, one per submission, max 10 MB each.** Anything else fails validation. One ZIP = one person's work; you need at least two submissions for a peer comparison to mean anything. `POST /check/upload-batch` takes at most 50 files per request. 5. **Starting a check spends credits and cannot be undone.** Check `quota.remaining` via `GET /account` first, and confirm with the user before calling `/check/start` on their behalf. Different engines cost different amounts — see `GET /test-types`. 6. **`check/create` is not idempotent.** Retrying a timed-out create makes a second check. On an ambiguous failure, call `GET /checks` and match on `name` before creating again. 7. **Timestamps are UTC strings** formatted `YYYY-MM-DD HH:MM:SS`. 8. **`GET /checks` is unpaged by default** and returns every check the account has ever created. On an established account that is a multi-megabyte response on every call. Pass `limit` (1-500) and `offset` to walk it instead. 9. **`location` and `source` on a match are opaque.** Pass them to `/check/getRemoteFile` exactly as received: `location` is a display label, `source` is the origin URL. Do not build either by hand, and do not swap them. You can only read a stored page one of your own submissions matched against. ## Typical flow 1. `POST /check/create` — create a check (returns its `id`; save it, every other call needs it as `check_id`). 2. `POST /check/upload` (or `/check/upload-batch`) — upload ZIP submission(s) to that check. 3. `POST /check/start` — queue analysis. **Spends credits.** 4. `POST /check/status` (or `GET /checks/{checkId}/status`) — poll every 20-30s until `status_id` is 4 (completed) or 3 (failed). 5. `POST /check/overview` then `POST /check/results` — read scores and detailed matches. `GET/POST /ai-results` for AI detection. Tip: `POST /check/quick` does create+upload+start in one multipart call. ## Status codes (status_id) 1 = New, 6 = Processing, 7 = Queued, 4 = Completed, 3 = Failed. Terminal states are 4 and 3 — stop polling when you reach either. Anything else means work is still in flight. ## Error handling Errors return a JSON body with an `error` string on every status code, whether or not you send an `Accept` header; validation failures (`422`) add a `validation_errors` object keyed by field name. | Status | Meaning | What an agent should do | | --- | --- | --- | | 401 | Missing or invalid API key | Stop and ask the user for a valid key. Do not retry. | | 402 | Account suspended for an unpaid invoice | Stop and tell the user to pay the invoice named in the `invoice` field. Every endpoint returns this until they do. Never retry. | | 403 | Key valid, plan lacks access to this engine or feature | Stop and report. Do not retry. | | 404 | The id does not exist or is not yours | Stop and report. Do not retry. | | 405 | Wrong HTTP verb for that path | Read the `Allow` response header and use one of those verbs. | | 409 | Check is not finished yet | Keep polling `/check/status`. | | 422 | Validation failed | Read `validation_errors`, fix the request, then retry once. | | 429 | Rate limit exceeded | Sleep for `Retry-After` seconds, then retry. | | 500 | Server error | Retry with exponential backoff, at most a few times. | Every response, successful ones included, carries `X-RateLimit-Limit` and `X-RateLimit-Remaining`. Read them to pace yourself rather than waiting to be refused. ## Webhooks (the alternative to polling) Set `callback_url` when you create a check, or an account-wide webhook URL in the dashboard under API Keys, and Codequiry POSTs to it when the check finishes. The per-check `callback_url` wins when both are set. The URL must be publicly reachable http(s); loopback and private addresses are rejected with `422` at create time. ```json { "event": "check.completed", "check_id": 12345, "name": "Week 4 essays", "course_id": 678, "status_id": 4, "status": "Completed", "submissions_count": 30, "avg_peer_similarity": 12.4, "avg_web_similarity": 3.1, "results_url": "https://dashboard.codequiry.com/course/678/assignment/12345", "timestamp": "2026-01-31T12:00:00+00:00" } ``` `event` is `check.completed` or `check.failed`. Each delivery carries `X-Codequiry-Event` and `X-Codequiry-Signature: sha256=`, an HMAC-SHA256 of the raw request body keyed with your API key. Verify it with a constant-time comparison before trusting the payload, and reply `2xx` to acknowledge. Delivery is best-effort, so keep polling as a fallback for checks you cannot afford to miss. ## Auth ### GET /auth/validate **Validate API key** Confirms the supplied `apikey` header is valid and returns the owning account. Responses: - `200` — Key is valid → { valid, user_id, email, name } (schema: KeyValidation) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. Example: ```bash curl -X GET "https://codequiry.com/api/v1/auth/validate" -H "apikey: YOUR_API_KEY" ``` ### POST /auth/validate **Validate API key (POST)** Identical to the GET form. Responses: - `200` — Key is valid → { valid, user_id, email, name } (schema: KeyValidation) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. Example: ```bash curl -X POST "https://codequiry.com/api/v1/auth/validate" -H "apikey: YOUR_API_KEY" ``` ### GET /account **Get account & quota** Returns the authenticated user's profile, plan, and remaining check quota. Responses: - `200` — Account info → { id, name, email, quota, submissions, is_pro, plan_id, edu_verified } (schema: Account) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. Example: ```bash curl -X GET "https://codequiry.com/api/v1/account" -H "apikey: YOUR_API_KEY" ``` ### POST /account **Get account & quota (POST)** Responses: - `200` — Account info → { id, name, email, quota, submissions, is_pro, plan_id, edu_verified } (schema: Account) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. Example: ```bash curl -X POST "https://codequiry.com/api/v1/account" -H "apikey: YOUR_API_KEY" ``` ### GET /status **Service status** Whether the checking engine (core) and its live-progress stream are up, from a one-minute cache shared with the dashboard's status badge. Poll this rather than the engine host itself; it costs one upstream probe a minute however many clients ask. Responses: - `200` — Engine status → { online, core, stream, latency_ms, cached_at, stale } (schema: EngineStatus) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. Example: ```bash curl -X GET "https://codequiry.com/api/v1/status" -H "apikey: YOUR_API_KEY" ``` ## Reference ### GET /languages **List supported languages** Languages you may pass to `language` when creating a check. Each entry includes the numeric `id` used by the API. Responses: - `200` — Language catalog → { success, count, languages } (schema: LanguageList) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. Example: ```bash curl -X GET "https://codequiry.com/api/v1/languages" -H "apikey: YOUR_API_KEY" ``` ### POST /languages **List supported languages (POST)** Responses: - `200` — Language catalog → { success, count, languages } (schema: LanguageList) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. Example: ```bash curl -X POST "https://codequiry.com/api/v1/languages" -H "apikey: YOUR_API_KEY" ``` ### GET /test-types **List engines (test types)** Returns the analysis engines available to your account. Use a returned `id` as `test_type` on create/start/quick. `default_test_type` is 1 and `recommended_test_type` is 9 (Group Similarity). Engine `id`s are live database ids, not a fixed sequence. Responses: - `200` — Engine catalog and your access → { success, test_types, user_access, default_test_type, recommended_test_type, note } (schema: TestTypeList) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `500` — Unexpected server error. Example: ```bash curl -X GET "https://codequiry.com/api/v1/test-types" -H "apikey: YOUR_API_KEY" ``` ### POST /test-types **List engines (test types) (POST)** Responses: - `200` — Engine catalog and your access → { success, test_types, user_access, default_test_type, recommended_test_type, note } (schema: TestTypeList) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `500` — Unexpected server error. Example: ```bash curl -X POST "https://codequiry.com/api/v1/test-types" -H "apikey: YOUR_API_KEY" ``` ## Checks ### GET /checks **List your checks** Returns every check (assignment) owned by the account, newest first, each with its status object. Unpaged by default for backwards compatibility; pass `limit` (and optionally `offset`) to page through a large account instead of pulling every check on each call. Parameters: - `limit` (query, integer, optional) — Maximum checks to return. Omit for all of them. - `offset` (query, integer, optional) — Checks to skip, newest first. Supplying offset without limit caps the page at 500. - `with_stats` (query, boolean, optional) — Attach a `stats` object to every check: submission counts, mean and max Group/Web/AI scores over finished submissions, flagged counts and the match total, so a list screen needs no per-check calls. Responses: - `200` — Array of checks → array of { stats, id, name, status_id, language_id, test_type, ai_run, base_code_detection, created_at, updated_at, assignmentstatuses } (schema: Check) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `422` — Request validation failed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. Example: ```bash curl -X GET "https://codequiry.com/api/v1/checks?limit=25&offset=0&with_stats=1" -H "apikey: YOUR_API_KEY" ``` ### POST /checks **List your checks (POST)** Identical to the GET form; `limit` and `offset` may be sent in the body. Request body (`application/json`): - `limit` (integer, optional) — - `offset` (integer, optional) — - `with_stats` (boolean, optional) — Attach a `stats` object to every check (see the GET form). Responses: - `200` — Array of checks → array of { stats, id, name, status_id, language_id, test_type, ai_run, base_code_detection, created_at, updated_at, assignmentstatuses } (schema: Check) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `422` — Request validation failed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. Example: ```bash curl -X POST "https://codequiry.com/api/v1/checks" -H "apikey: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"limit":25,"offset":0,"with_stats":true}' ``` ### POST /check/create **Create a check** Creates an empty check. Only `name` is required; `language` and `test_type` are optional and default to 13 and 1 respectively. Request body (`application/json`): - `name` (string, required) — Check name. - `language` (integer, optional, default 13) — Language id from GET /languages. Use 999 for Auto Detect; an unknown/invalid id falls back to Auto Detect instead of returning an error. - `test_type` (integer, optional, default 1) — Engine id from GET /test-types. - `ai_run` (boolean, optional, default 1) — Run AI-generated-code detection on this check. Accepts true/false/1/0. - `base_code_detection` (boolean, optional, default ) — Detect shared base/boilerplate (starter) code. - `callback_url` (string, optional) — Webhook destination for this check. Codequiry POSTs a signed JSON payload here when the check completes or fails, so you do not have to poll. Must be a publicly reachable http(s) URL - loopback, private and link-local addresses are rejected with 422. Overrides the account-level webhook URL set in Dashboard -> API Keys. See the Webhooks section of the API description. Responses: - `201` — Created check → { id, name, status_id, language_id, test_type, ai_run, base_code_detection, job_id, created_at, updated_at } (schema: CheckCreated) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `422` — Request validation failed. Example: ```bash curl -X POST "https://codequiry.com/api/v1/check/create" -H "apikey: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"name":"CS-201 Assignment 4","language":13,"test_type":1,"ai_run":true,"base_code_detection":false,"callback_url":"https://example.edu/hooks/codequiry"}' ``` ### POST /check/get **Get a check** Returns a check with its status, submission count, and submissions. Request body (`application/json`): - `check_id` (integer, required) — Responses: - `200` — Check detail → { check, status, submission_count, submissions } - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `422` — Request validation failed. Example: ```bash curl -X POST "https://codequiry.com/api/v1/check/get" -H "apikey: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"check_id":12345}' ``` ### POST /check/update **Update a check** Renames a check and/or changes its language. Equivalent to PATCH /checks/{checkId}. Request body (`application/json`): - `check_id` (integer, required) — - `name` (string, optional) — - `language` (integer, optional) — Language id from GET /languages. Use 999 for Auto Detect. As on /check/create, an unknown or invalid id falls back to Auto Detect and still returns 200 - the check is never left pointing at a language that does not exist, but a typo will not be reported either. Responses: - `200` — Updated check → { success, message, check } - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `403` — Not permitted (e.g. free-trial limitation, or a read-only demo check). - `404` — Resource not found or not owned by this account. - `422` — Request validation failed. Example: ```bash curl -X POST "https://codequiry.com/api/v1/check/update" -H "apikey: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"check_id":12345,"name":"CS-201 Assignment 4 (regrade)","language":13}' ``` ### GET /checks/{checkId} **Get a check (REST)** Retrieves a check with its status, submission count, and submissions. Equivalent to POST /check/get. Parameters: - `checkId` (path, integer, required) — The check (assignment) id. Responses: - `200` — Check detail → { check, status, submission_count, submissions } - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `422` — Request validation failed. Example: ```bash curl -X GET "https://codequiry.com/api/v1/checks/12345" -H "apikey: YOUR_API_KEY" ``` ### PATCH /checks/{checkId} **Update a check (REST)** Parameters: - `checkId` (path, integer, required) — The check (assignment) id. Request body (`application/json`): - `name` (string, optional) — - `language` (integer, optional) — Language id from GET /languages. Use 999 for Auto Detect. An unknown or invalid id falls back to Auto Detect and still returns 200. Responses: - `200` — Updated check → { success, message, check } - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `403` — Not permitted (e.g. free-trial limitation, or a read-only demo check). - `404` — Resource not found or not owned by this account. - `422` — Request validation failed. Example: ```bash curl -X PATCH "https://codequiry.com/api/v1/checks/12345" -H "apikey: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"name":"CS-201 Assignment 4 (regrade)","language":13}' ``` ### DELETE /checks/{checkId} **Delete a check (REST)** Parameters: - `checkId` (path, integer, required) — The check (assignment) id. Responses: - `200` — Deleted → { success, message, check_id, check_name } (schema: DeleteResult) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `403` — Not permitted (e.g. free-trial limitation, or a read-only demo check). - `404` — Resource not found or not owned by this account. - `409` — Check is in a state that does not allow this operation (e.g. still processing, or not yet completed). Example: ```bash curl -X DELETE "https://codequiry.com/api/v1/checks/12345" -H "apikey: YOUR_API_KEY" ``` ### POST /check/delete **Delete a check** Equivalent to DELETE /checks/{checkId}. Free-trial and demo checks cannot be deleted (403); a processing check cannot be deleted (409). Request body (`application/json`): - `check_id` (integer, required) — Responses: - `200` — Deleted → { success, message, check_id, check_name } (schema: DeleteResult) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `403` — Not permitted (e.g. free-trial limitation, or a read-only demo check). - `404` — Resource not found or not owned by this account. - `409` — Check is in a state that does not allow this operation (e.g. still processing, or not yet completed). - `422` — Request validation failed. Example: ```bash curl -X POST "https://codequiry.com/api/v1/check/delete" -H "apikey: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"check_id":12345}' ``` ## Submissions ### POST /check/upload **Upload a submission (ZIP)** Uploads one ZIP archive of source code into a check. Max 10 MB. Call once per submission, or use /check/upload-batch. Request body (`multipart/form-data`): - `check_id` (integer, required) — Target check id. - `file` (string, required) — ZIP archive (mimes:zip, max 10 MB). Responses: - `200` — Upload accepted → { data, file, file_size, submission_count, check } (schema: UploadResult) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `403` — Not permitted (e.g. free-trial limitation, or a read-only demo check). - `422` — Request validation failed. - `500` — Unexpected server error. Example: ```bash curl -X POST "https://codequiry.com/api/v1/check/upload" -H "apikey: YOUR_API_KEY" -F "check_id=12345" -F "file=@nowak_alice_a4.zip" ``` ### POST /check/upload-batch **Upload many submissions** Uploads 1-50 ZIP files into a check in one request. Validation is all-or-nothing: if any file is not a ZIP, is over 10 MB, or is not a file at all, the whole batch is rejected with 422 and nothing is stored - check the files before sending them. A file that passes validation but fails while being stored is reported in `failed_uploads`, alongside the ones that succeeded, with a 200 response. Request body (`multipart/form-data`): - `check_id` (integer, required) — - `files` (array, required) — 1–50 ZIP archives (each mimes:zip, max 10 MB). Responses: - `200` — Batch processed → { success, message, uploaded, uploaded_count, failed_count, failed_uploads, check } (schema: BatchUploadResult) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `403` — Not permitted (e.g. free-trial limitation, or a read-only demo check). - `422` — Request validation failed. - `500` — Unexpected server error. Example: ```bash curl -X POST "https://codequiry.com/api/v1/check/upload-batch" -H "apikey: YOUR_API_KEY" -F "check_id=12345" -F "files=@nowak_alice_a4.zip" ``` ### POST /check/deleteSubmission **Delete a submission** Removes one submission from a check. Not available on free trials (403) or demo checks (403). Request body (`application/json`): - `check_id` (integer, required) — - `submission_id` (integer, required) — Responses: - `200` — Deleted → { success, message } - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `403` — Not permitted (e.g. free-trial limitation, or a read-only demo check). - `422` — Request validation failed. - `500` — Unexpected server error. Example: ```bash curl -X POST "https://codequiry.com/api/v1/check/deleteSubmission" -H "apikey: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"check_id":12345,"submission_id":90271}' ``` ## Run ### POST /check/start **Start a check** Queues analysis for a check that already has submissions. `webcheck` and `dbcheck` only take effect when BOTH are supplied (both true → engine 1, both false → engine 9); otherwise the check's existing engine is used. The check is set to status_id 7 (queued). Request body (`application/json`): - `check_id` (integer, required) — - `webcheck` (boolean, optional) — Enable internet/web matching. - `dbcheck` (boolean, optional) — Enable Codequiry database matching. - `test_type` (integer, optional) — Approved engine id (overrides webcheck/dbcheck mapping). - `ai_run` (boolean, optional, default 1) — Run AI-generated-code detection on this check. Accepts true/false/1/0. - `base_code_detection` (boolean, optional, default ) — Detect shared base/boilerplate (starter) code. Responses: - `200` — Check queued → { success, check, status, submission_count, checkURL } - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `403` — Not permitted (e.g. free-trial limitation, or a read-only demo check). - `409` — Check is in a state that does not allow this operation (e.g. still processing, or not yet completed). - `422` — Request validation failed. - `503` — Analysis services are temporarily offline. → { error } (schema: Error) Example: ```bash curl -X POST "https://codequiry.com/api/v1/check/start" -H "apikey: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"check_id":12345,"webcheck":true,"dbcheck":true,"test_type":1,"ai_run":true,"base_code_detection":false}' ``` ### POST /check/quick **Quick check (all-in-one)** Creates a check, uploads files, and starts analysis in a single authenticated call. Distinct from the public website Quick Check widget. Request body (`multipart/form-data`): - `name` (string, required) — - `language` (integer, optional, default 13) — Language id from GET /languages. Use 999 for Auto Detect; an unknown/invalid id falls back to Auto Detect. - `files` (array, required) — One or more ZIP archives (each mimes:zip, max 10 MB). - `webcheck` (boolean, optional) — - `dbcheck` (boolean, optional) — - `test_type` (integer, optional) — - `ai_run` (boolean, optional, default 1) — Run AI-generated-code detection on this check. Accepts true/false/1/0. - `base_code_detection` (boolean, optional, default ) — Detect shared base/boilerplate (starter) code. Responses: - `201` — Created and started → { success, message, data, next_steps } (schema: QuickCheckResult) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `422` — Request validation failed. - `500` — Unexpected server error. - `503` — Analysis services are temporarily offline. → { error } (schema: Error) Example: ```bash curl -X POST "https://codequiry.com/api/v1/check/quick" -H "apikey: YOUR_API_KEY" -F "name=CS-201 Assignment 4" -F "language=13" -F "files=@nowak_alice_a4.zip" -F "webcheck=1" -F "dbcheck=1" -F "test_type=1" -F "ai_run=1" -F "base_code_detection=" ``` ### POST /check/status **Get check status** Polling endpoint. Equivalent to GET /checks/{checkId}/status. Request body (`application/json`): - `check_id` (integer, required) — Responses: - `200` — Status → { check_id, status_id, status, status_message, progress, submissions_total, submissions_completed, estimated_completion } (schema: CheckStatus) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `404` — Resource not found or not owned by this account. - `422` — Request validation failed. Example: ```bash curl -X POST "https://codequiry.com/api/v1/check/status" -H "apikey: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"check_id":12345}' ``` ### GET /checks/{checkId}/status **Get check status (REST)** Parameters: - `checkId` (path, integer, required) — The check (assignment) id. Responses: - `200` — Status → { check_id, status_id, status, status_message, progress, submissions_total, submissions_completed, estimated_completion } (schema: CheckStatus) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `404` — Resource not found or not owned by this account. - `422` — Request validation failed. Example: ```bash curl -X GET "https://codequiry.com/api/v1/checks/12345/status" -H "apikey: YOUR_API_KEY" ``` ## Results ### POST /check/overview **Get results overview** Per-submission similarity scores and bar-chart data. The check must be completed (status_id 4) or you get 409. Request body (`application/json`): - `check_id` (integer, required) — Responses: - `200` — Overview → { overviewURL, submissions, bardata } - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `409` — Check is in a state that does not allow this operation (e.g. still processing, or not yet completed). - `422` — Request validation failed. Example: ```bash curl -X POST "https://codequiry.com/api/v1/check/overview" -H "apikey: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"check_id":12345}' ``` ### POST /check/overviewCSV **Get overview as CSV** Streams a CSV download with columns Submission,Score. Requires a completed check. Request body (`application/json`): - `check_id` (integer, required) — Responses: - `200` — CSV file → string - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `409` — Check is in a state that does not allow this operation (e.g. still processing, or not yet completed). - `422` — Request validation failed. Example: ```bash curl -X POST "https://codequiry.com/api/v1/check/overviewCSV" -H "apikey: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"check_id":12345}' ``` ### POST /check/results **Get detailed results** Full match detail for one submission, including peer, web/external, and AI matches. Request body (`application/json`): - `check_id` (integer, required) — - `submission_id` (integer, required) — Responses: - `200` — Detailed results → { submission, avg, max, min, other_matches, related_submissions, related_files } - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `409` — Check is in a state that does not allow this operation (e.g. still processing, or not yet completed). - `422` — Request validation failed. Example: ```bash curl -X POST "https://codequiry.com/api/v1/check/results" -H "apikey: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"check_id":12345,"submission_id":90271}' ``` ### POST /check/getRemoteFile **Get a matched web file** Fetches the stored content of an external/web match. `location` and `source` come verbatim from a match object in /check/results - do not construct them by hand. You may only read a stored file that one of your own submissions matched against: a file that exists but belongs to another account returns 403, and a location/source pair that matches nothing returns 404. Request body (`application/json`): - `location` (string, required) — - `source` (string, required) — Responses: - `200` — Stored web file → { file } - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `403` — Not permitted (e.g. free-trial limitation, or a read-only demo check). - `404` — Resource not found or not owned by this account. - `422` — Request validation failed. Example: ```bash curl -X POST "https://codequiry.com/api/v1/check/getRemoteFile" -H "apikey: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"location":"src/BankAccount.java","source":"https://github.com/example-org/banking-utils/blob/main/src/BankAccount.java"}' ``` ### GET /ai-results **Get AI detection results** AI-generated-code detection and code-quality analysis for every submission in a check. Parameters: - `assignment_id` (query, integer, required) — Check id. Responses: - `200` — AI results → { success, assignment_id, assignment_name, message, assignment_status, statistics, submissions } (schema: AIResults) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `404` — Resource not found or not owned by this account. - `422` — Request validation failed. Example: ```bash curl -X GET "https://codequiry.com/api/v1/ai-results?assignment_id=12345" -H "apikey: YOUR_API_KEY" ``` ### POST /ai-results **Get AI detection results (POST)** Request body (`application/json`): - `assignment_id` (integer, required) — Responses: - `200` — AI results → { success, assignment_id, assignment_name, message, assignment_status, statistics, submissions } (schema: AIResults) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `404` — Resource not found or not owned by this account. - `422` — Request validation failed. Example: ```bash curl -X POST "https://codequiry.com/api/v1/ai-results" -H "apikey: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"assignment_id":12345}' ``` ### POST /check/summary **Get check summary** Aggregate stats for a check. Equivalent to GET /checks/{checkId}/summary. Request body (`application/json`): - `check_id` (integer, required) — Responses: - `200` — Summary → { check_id, check_name, status, status_id, submission_count, completed_submissions, plagiarism_stats, ai_detection_stats, flagged_submissions, processing_time_seconds, created_at, updated_at } (schema: CheckSummary) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `404` — Resource not found or not owned by this account. - `422` — Request validation failed. Example: ```bash curl -X POST "https://codequiry.com/api/v1/check/summary" -H "apikey: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"check_id":12345}' ``` ### GET /checks/{checkId}/summary **Get check summary (REST)** Parameters: - `checkId` (path, integer, required) — The check (assignment) id. Responses: - `200` — Summary → { check_id, check_name, status, status_id, submission_count, completed_submissions, plagiarism_stats, ai_detection_stats, flagged_submissions, processing_time_seconds, created_at, updated_at } (schema: CheckSummary) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `404` — Resource not found or not owned by this account. - `422` — Request validation failed. Example: ```bash curl -X GET "https://codequiry.com/api/v1/checks/12345/summary" -H "apikey: YOUR_API_KEY" ``` ### POST /check/export **Export results** Exports a completed check as JSON or CSV (`format`, default csv). Equivalent to GET /checks/{checkId}/export. Request body (`application/json`): - `check_id` (integer, required) — - `format` (string, optional, default csv) — Responses: - `200` — Export (JSON body or CSV download) → { check_id, check_name, export_date, submissions } (schema: ExportResult) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `404` — Resource not found or not owned by this account. - `409` — Check is in a state that does not allow this operation (e.g. still processing, or not yet completed). - `422` — Request validation failed. Example: ```bash curl -X POST "https://codequiry.com/api/v1/check/export" -H "apikey: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"check_id":12345,"format":"csv"}' ``` ### GET /checks/{checkId}/export **Export results (REST)** Parameters: - `checkId` (path, integer, required) — The check (assignment) id. - `format` (query, string, optional) — Responses: - `200` — Export (JSON body or CSV download) → { check_id, check_name, export_date, submissions } (schema: ExportResult) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — The account is suspended for an unpaid invoice. Every endpoint returns this until the invoice is paid from the billing dashboard; it is not retryable and the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `404` — Resource not found or not owned by this account. - `409` — Check is in a state that does not allow this operation (e.g. still processing, or not yet completed). - `422` — Request validation failed. Example: ```bash curl -X GET "https://codequiry.com/api/v1/checks/12345/export?format=csv" -H "apikey: YOUR_API_KEY" ``` ### POST /check/viewer **Results viewer payload** Everything the dashboard's results page loads for one submission, in one call: the submission's files (the first one with content inline, the rest fetched through /check/viewer/file), its peer and AI matches, its web sources collapsed to one entry per source, and a rail of every submission in the check carrying the Group, Web and AI scores the dashboard prints beside each name. Built by the same loader as the dashboard, so the two never disagree. Omit submission_id for the highest-scoring submission. Results that are paywalled on the account answer 402 with `paywalled: true`. Request body (`application/json`): - `check_id` (integer, required) — - `submission_id` (integer, optional) — Which submission to load. Omit for the highest-scoring one. Responses: - `200` — Viewer payload → { success, check, submission, rail, submissions, files, matches, web_files, ai_files, stats, avg, max, min, dashboard_url, meta } (schema: ViewerResults) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — Payment required. Either the account is suspended for an unpaid invoice (every endpoint answers this until it is paid), or results are paywalled on this account until it upgrades (the viewer endpoints only). `paywalled` tells the two apart; the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `404` — Resource not found or not owned by this account. - `422` — Request validation failed. Example: ```bash curl -X POST "https://codequiry.com/api/v1/check/viewer" -H "apikey: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"check_id":12345,"submission_id":90271}' ``` ### POST /check/viewer/file **Results viewer: one submission file** The stored text of one of a submission's own files, for the viewer's file tabs. /check/viewer ships content for the first file only; fetch the others here by their `filedir`. Resolved the way the dashboard resolves them: the engine's cache under every spelling of the path, then the submission's stored archive. Request body (`application/json`): - `check_id` (integer, required) — - `submission_id` (integer, required) — - `file_path` (string, required) — The file's `filedir` from the viewer payload. Responses: - `200` — File text → { success, content, filedir } (schema: ViewerFile) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — Payment required. Either the account is suspended for an unpaid invoice (every endpoint answers this until it is paid), or results are paywalled on this account until it upgrades (the viewer endpoints only). `paywalled` tells the two apart; the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `404` — Resource not found or not owned by this account. - `422` — Request validation failed. Example: ```bash curl -X POST "https://codequiry.com/api/v1/check/viewer/file" -H "apikey: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"check_id":12345,"submission_id":90271,"file_path":"nowak_alice_a4/BankAccount.java"}' ``` ### POST /check/viewer/counterpart **Results viewer: the other side of a match** The code a match was found against: the peer submission's file for a peer match, or the cached copy of the external source for a web match, with the line ranges on both sides so a client can draw the comparison. AI matches have no counterpart. A web entry flagged `is_legacy_web` carries an id from a different table; send `legacy: true` for those. 404 means the source's text is simply not stored, which is a normal state for older web sources. Request body (`application/json`): - `check_id` (integer, required) — - `submission_id` (integer, required) — - `match_id` (integer, required) — The `id` of an entry in `matches` or `web_files`. - `legacy` (boolean, optional) — true when the entry's `is_legacy_web` is true. Responses: - `200` — Counterpart text and line ranges → { success, file, match } (schema: ViewerCounterpart) - `401` — Missing or invalid API key. The API key is checked before any endpoint logic runs, so this is returned for every operation. - `402` — Payment required. Either the account is suspended for an unpaid invoice (every endpoint answers this until it is paid), or results are paywalled on this account until it upgrades (the viewer endpoints only). `paywalled` tells the two apart; the request was not performed. - `429` — Rate limit exceeded: more than 60 requests in one minute from this IP. Retry after the number of seconds in the Retry-After header. Successful responses carry X-RateLimit-Limit and X-RateLimit-Remaining too, so you can pace a client without waiting to be refused. - `404` — Resource not found or not owned by this account. - `422` — Request validation failed. Example: ```bash curl -X POST "https://codequiry.com/api/v1/check/viewer/counterpart" -H "apikey: YOUR_API_KEY" -H "Content-Type: application/json" -d '{"check_id":12345,"submission_id":90271,"match_id":1849201,"legacy":false}' ``` --- Generated from public/openapi.json by scripts/build-api-docs.php. Do not edit by hand.