ClassMarker
BUSINESS · TASKS
Exam results, the question bank, and its categories in the account they connected.
Acts as the person, not as itself
Each user connects their own account. Every call carries both identities — the agent and the person it is acting for — so the agent can never reach past what that individual can already do.
Credentials never touch the agent
Tokens live in the vault and attach server-side at call time. The agent holds a session, not a secret, and revoking access does not mean rotating a key.
Every call on the record
Who asked, which agent acted, which action ran, and the verdict that let it through — one audit trail across every integration, not one per vendor.
What an agent can do
Each action is granted on its own. An agent allowed to read is not thereby allowed to write, and the scope beside each row is what the acting user must have connected for it to run at all.
classmarker_delete_v1_accesslists_by_access_list_id_jsonWRITERemove access codes from an access list. DELETE /v1/accesslists/{access_list_id}.json. Removes up to 100 access codes from an API-controlled access list, revoking those codes' ability to start the exam. The list is named by path; the body is a JSON ARRAY OF STRINGS naming WHICH codes to remove, and it is not optional -- a delete that names no code is a delete that says nothing. Irreversible: re-adding a code is a separate call.
classmarker_get_v1_categories_jsonREADList question-bank categories. GET /v1/categories.json. Returns the whole category tree of the question bank: every parent category with the categories nested under it. Every account has the built-in `Generic Parent` (id 0) containing `Generic` (id 0). A parent with no children reports `categories: null` rather than an empty list.
classmarker_get_v1_groups_by_group_id_tests_by_test_id_recent_results_jsonREADGet recent results for one group exam. GET /v1/groups/{group_id}/tests/{test_id}/recent_results.json. Returns results for ONE exam inside ONE group, finished after a given moment. Narrower than the all-groups call and the right one when the group and exam are already known. An id that does not exist is not an error: the response is `no_results`, indistinguishable from a real exam nobody has taken, so confirm ids with the discovery call rather than reading an empty result as a wrong id.
classmarker_get_v1_groups_recent_results_jsonREADGet recent results across all groups. GET /v1/groups/recent_results.json. Returns exam results finished after a given moment, across every Group in the account. Use this to poll for new results; ClassMarker's own real-time delivery is webhooks, and this is the pull equivalent.
classmarker_get_v1_jsonREADList your groups, links and exams. GET /v1.json. Returns every Group and every Link in the ClassMarker account, each with the exams assigned to it, so a later call can name a specific group_id/test_id or link_id/test_id. This is the discovery call: start here when you do not already know the ids. Answers `no_results` with empty `groups` and `links` arrays on an account that has none.
classmarker_get_v1_links_by_link_id_tests_by_test_id_recent_results_jsonREADGet recent results for one link exam. GET /v1/links/{link_id}/tests/{test_id}/recent_results.json. Returns results for ONE exam behind ONE link, finished after a given moment. As with the group call, an unknown id answers `no_results` rather than an error.
classmarker_get_v1_links_recent_results_jsonREADGet recent results across all links. GET /v1/links/recent_results.json. Returns exam results finished after a given moment, across every Link in the account. The Link equivalent of the groups call: a Link is a public URL anyone can take the exam from, a Group is a roster of named test-takers.
classmarker_get_v1_questions_by_question_id_jsonREADGet one question. GET /v1/questions/{question_id}.json. Returns a single question from the question bank by id. A question id the account does not own answers `no_results` rather than an error.
classmarker_get_v1_questions_jsonREADList question-bank questions. GET /v1/questions.json. Returns one page of the account's question bank, each question with its type, category, text, options, correct answers, points and feedback. Paged: pass `page` to walk it. A page past the end is not an error -- it answers `ok` with an empty `questions` array.
classmarker_post_v1_accesslists_by_access_list_id_jsonWRITEAdd access codes to an access list. POST /v1/accesslists/{access_list_id}.json. Adds up to 100 access codes to an API-controlled access list, so the holders of those codes can start the exam the list guards. The list is named by path; the body is a JSON ARRAY OF STRINGS, one code per entry, each at most 255 characters. An access list id the account does not own answers `incorrectUrlId`.
classmarker_post_v1_categories_category_jsonWRITECreate a category. POST /v1/categories/category.json. Creates a category inside a parent category and returns its `category_id`. Both `category_name` and `parent_category_id` are required; use parent 0 (`Generic Parent`) when there is no better home. Names must be unique across the account. `verify_only` validates without creating.
classmarker_post_v1_categories_parent_category_jsonWRITECreate a parent category. POST /v1/categories/parent_category.json. Creates a top-level category in the question bank and returns its `parent_category_id`. Names must be unique: a duplicate answers `payloadValidationError` with `Parent category name already exists`. Pass `verify_only` to validate the payload without creating anything -- the response is `status: verified`.
classmarker_post_v1_questions_jsonWRITEAdd a question to the question bank. POST /v1/questions.json. Creates a question and returns it with its assigned `question_id`. Read the `body` schema before calling: ClassMarker's option format is specific and it rejects the obvious guesses. `verify_only` validates the payload without creating anything.
classmarker_put_v1_categories_parent_category_by_parent_category_id_jsonWRITERename a parent category. PUT /v1/categories/parent_category/{parent_category_id}.json. Renames an existing top-level category. Send `parent_category_name` alone: `parent_category_id` is read-only and including it is refused, even though it is the id in the path. An id the account does not own answers `incorrectUrlId`. `verify_only` works here too.
classmarker_put_v1_questions_by_question_id_jsonWRITEUpdate a question. PUT /v1/questions/{question_id}.json. Replaces an existing question. Send the WHOLE question, not a patch: the same fields the create call takes. A question id the account does not own answers `incorrectUrlId`. `verify_only` validates without saving.
Often connected alongside
Put ClassMarker behind one governed endpoint.
Same permissions, same audit trail, whatever else you connect next.