dry_run, then submit. The server validates exactly like a save in the web
app, then scores and persists a new evaluation.
All requests authenticate with an X-Aegister-Token header (see
Authentication and API token).
The organization must hold the v_ciso license. Reading needs the view role; writing
needs the edit role (security_officer, owner, or super_admin).
Paths below are abbreviated as
.../workflows/{wid}/.... The full base is
https://app.aegister.com/api/v1/v-ciso/organizations/{oid}. All responses use the house
envelope { "error": 0|1, "messages": [], "data": {…} } (plus "total" on lists).Before you start
This guide starts from an existing organization that already holds thev_ciso license and
has the framework you want to fill associated and configured. You only need its organization
id ({oid}) and a token with the edit role (security_officer, owner, or super_admin).
1. Discover what to fill
List every task (table and question) in the org, each with itstype, so a script can
locate what to work on. Filter with ?type=table or ?type=questions.
workflow_id + task_id for the per-task calls. The older
GET .../table-tasks (List table tasks) returns only table tasks; /tasks covers both.
2. Table tasks (rows)
Read the spec (the contract)
type, required, a declarative format (for example
{ "kind": "date", "pattern": "YYYY-MM-DD" }), and allowed choices (with both the
value id and localized label). Dependent columns carry depends_on +
choices_by_parent; cross-task columns carry source. Send either the choice label or
its value id; multi-value columns accept an array or a |-joined string.
Validate without writing (dry_run)
errors (a column id that is not in the spec, wrong choice, bad date/number, a child
value not allowed for its parent, an unknown cross-task value) and re-run until error_count is 0.
Messages and column labels follow ?lan=en|it (English by default); a required value that is
missing carries "code": "required", so a script can tell it apart without parsing the text.
current lets you compare what you send with what the table holds before you submit. It holds
the cells as the console shows them (localized text, choices as labels), so don’t send it back as
rows: build your rows from the spec.
The JSON body must carry a rows array: without it the request fails with 400 and
Missing 'rows' array. dry_run counts only when it is true, 1 or yes (in the body or as
a query parameter); any other value means submit.
Replace the table, or keep the rows you don’t send
By default the rows you send replace the whole table. Add"keep_rows": true (or
?keep_rows=1, or a keep_rows form field with an XLSX upload) to update it instead: a row
whose first column matches a row already in the table replaces that row, new rows go at the
end, and the rows you did not send stay. It is read like dry_run (true, 1 or yes).
kept_count, the number of current rows that stay.
Submit
Dropdry_run to persist. The server validates again, submits to the scoring engine, and
records a new evaluation, exactly like a save in the web app.
keep_rows, the response also carries kept_rows.
A request with any validation error returns 400 with error: 1 and the data.errors
list; nothing is written.
3. Question tasks (answers)
Question tasks use the same/spec and /import endpoints; the payload key is
answers instead of rows. Read the spec and current answers in one call to prefill,
then submit.
Unknown id: not a question of this task or step (see /spec)).
{ "value", "evidence": [<path>], "note": [{ "id", "response" }] }. Upload the file first
(see section 5) and use the returned path: it must be a
file uploaded for the same organization, workflow and question, or the answer is rejected.
Each note id must be one of the question’s notes in /spec; for a task question it is
<question_id>_justification:
dry_run to persist; the response carries the new evaluation_id, same as tables.
4. Framework controls
A workflow’s framework (the control set behind the score) has its own spec/answers/submit trio, grouped into steps. Work one step at a time with?step=<stepId>.
id, label, description, type
(radio|select|checkbox|date|number|text|…), choices, required, an evidence flag
(whether files may be attached), notes (the justification boxes, each with its id), step,
subframework, category, and weight. A control id that is not in the step is an error.
Submit a step’s answers with controls-import: dry_run first, then persist.
id is the one listed in the control’s notes (for NIS 2 controls, for example
2.1.1_justification):
value together with the note. On ISO 27001, an answer that carries only a
justification, with no value, erases the control’s level.
Dropping dry_run validates then submits via /evaluate (Aegister scores and persists),
returning { "submitted": <number of answers>, "step": "E", "evaluation_id": … }.
5. Evidence: the two-step upload
Upload evidence separately, not inline. Send the file to its artifact, then reference the returnedpath in the answer.
Step 1, upload the file as base64 JSON to the artifact (a control id or question id):
413); allowed formats are PDF, Word
(.doc/.docx), Excel (.xls/.xlsx), images, and video (anything else returns 400). Uploads
dedupe by SHA-256 (identical content returns the existing version, 200, instead of a new
201), and only the latest 10 versions per artifact are kept.
Step 2, reference the returned path in the evidence array of the answer you submit
(sections 3 and 4).
To list existing evidence across a workflow (every artifact with its latest version and full
history), call GET .../workflows/{wid}/documents (List documents in the sidebar).
Per-artifact history and downloads use the other endpoints in the V-CISO → Cyber Posture → Documents group.
6. Fill a task from your documents (AI)
If the answers already live in your documents (a policy, an asset list, a register), let the AI read them and propose what to put in a table or question task. It is the same proposal as Fill from your documents in the console. Nothing is saved: you review the proposal and submit it through/import as in sections 2 and 3.
Step 1, start the job with 1 to 5 documents in base64 (at most 10 MB each, 20 MB in all, else
413). You can start 20 jobs an hour; past that the call answers 429:
skipped with
the reason. The call fails with 400 when no document can be read, and with 502 when the AI
service cannot be reached.
Step 2, poll the job until status is done:
{ "status": "running" }. When the documents hold nothing for the
task, the result carries a msg instead of a proposal. For a question task, kind is
questions and the proposal is under answers, keyed by question id. ai explains the
proposal: a summary, how many items were filled, for each answer the confidence and the document
it came from, and the rows left out with the reason (for example a value missing from a linked
list, which you add there first).
Step 3, submit the proposal: send rows (tables) or answers (questions) to /import,
dry_run first. Only the person who started the job can read it, and the documents are not kept.
