Wiki Standards

/api/wiki

Read and edit the open SynC Standards wiki. Reads are public — no API key needed. Writes require the relevant wiki permission.

Endpoints

GET /api/wiki/libraries

List wiki standard libraries with standard count.

GET /api/wiki/libraries/:slug

Get a wiki library by slug with its full category tree and standards list. Supports search.

Parameters
NameInTypeDescription
slugpathstringLibrary URL slug
searchquerystringFilter standards by title or description (ILIKE match)

GET /api/wiki/standards/:librarySlug/:standardSlug

Get a wiki standard by library and standard slug, including current revision content (markdown).

Parameters
NameInTypeDescription
librarySlugpathstringLibrary URL slug
standardSlugpathstringStandard URL slug

GET /api/wiki/standards/:id/revisions

List revision history for a wiki standard. Paginated.

Parameters
NameInTypeDescription
idpathstringStandard UUID
limitqueryintegerResults per page (default 50)
offsetqueryintegerOffset for pagination (default 0)

GET /api/wiki/standards/:id/revisions/:revId

Get a specific wiki standard revision with full markdown content.

Parameters
NameInTypeDescription
idpathstringStandard UUID
revIdpathstringRevision UUID

GET /api/wiki/standards/:id/diff/:fromRev/:toRev

Compare two revisions with computed diff. Returns both full documents, a structured hunks array (added/removed/unchanged lines), stats (added/removed counts), and a unified diff patch string.

Parameters
NameInTypeDescription
idpathstringStandard UUID
fromRevpathstringSource revision UUID
toRevpathstringTarget revision UUID

GET /api/wiki/standards/:id/citations

List the documents that cite this standard ("what cites this?"), from the compiled citation index. Rows carry citingEntityType: "wiki_standard" (a wiki document, addressed by librarySlug/slug) or "standard" (a main-site standard, whose citingEntityId is an INTEGER for /standard/:id). Paginated over DOCUMENTS. Returns two distinct counts: citingDocumentCount (distinct citing documents) and citationOccurrenceCount (individual references — one document may cite the standard many times). Both counts and the rows are viewer-scoped, so a caller who cannot read a citing document neither sees it nor sees it counted; the counts may therefore be lower than the unfiltered totals. A third count, privateCitationOccurrenceCount, aggregates the references made by main-site standards the caller may not read: it says such citers exist and never identifies them. A standard the caller cannot read returns 404, identically to one that does not exist.

Parameters
NameInTypeDescription
idpathstringStandard UUID (the CITED standard)
limitqueryintegerCiting documents per page, 1-100 (default 25)
offsetqueryintegerOffset for pagination (default 0)

GET /api/wiki/standards/:id/adopted

List adopted (stable) revisions for a wiki standard. Revoked editions are omitted for everyone but a wiki moderator, who also sees revoked_at and revoked_reason_code on the row, plus an `effect` object on any row under an open revocation window (level, reason_code, revoked_at, replacement_available_at, replacement_adopted_revision_id, level2_at and the derived deadlines). `effect` is absent for every non-moderator caller.

Parameters
NameInTypeDescription
idpathstringStandard UUID

GET /api/wiki/standards/:id/adopted/:revNum

Get a specific adopted revision by revision number. A revoked edition 404s for everyone but a wiki moderator.

Parameters
NameInTypeDescription
idpathstringStandard UUID
revNumpathintegerAdopted revision number

POST /api/wiki/standards/validate

Validate in-flight standard markdown without saving. Returns blocking and advisory findings (each with a rule, severity, line, field, and message). Content that fails validation still returns 200 with hasBlocking:true — reporting failures is the job of this endpoint, not a 4xx. Cross-reference findings are advisory and appear only when categoryId or standardId is supplied; they never block. When standardId is supplied it also returns impact: the citation consequences of this edit, viewer-scoped and never blocking. impact.removedClauses lists each cited clause the edit disturbs with a disposition of removed (no successor could be traced — NOT a proven deletion), relocated (the requirement is now at impact.removedClauses[].movedTo), or reoccupied (the address survives but numbers a different requirement now). CONTRIBUTOR-GATED: wiki:standard:* permissions come from the SiteContributor role, which you are granted by accepting the Contributor License Agreement (CLA). The account owner accepts it signed in, from their profile or the wiki; an API key cannot accept it. Until the account (for an API key, its OWNER) has accepted, this endpoint returns 403 no matter what the key was granted, and /api/whoami lists the permission under `dormant` with that step as its `remedy`.

Required permission: wiki:standard:create

Request body (JSON)

Required
Optional

categoryId/standardId are used only to resolve the category path and run the DB-aware cross-reference advisory.

POST /api/wiki/standards

Create a new wiki standard. Content is markdown, optionally with YAML frontmatter. If frontmatter is missing, it is auto-generated from the body params (title, description, category). Frontmatter is the source of truth for metadata — if present, it overrides body params. CONTRIBUTOR-GATED: wiki:standard:* permissions come from the SiteContributor role, which you are granted by accepting the Contributor License Agreement (CLA). The account owner accepts it signed in, from their profile or the wiki; an API key cannot accept it. Until the account (for an API key, its OWNER) has accepted, this endpoint returns 403 no matter what the key was granted, and /api/whoami lists the permission under `dormant` with that step as its `remedy`.

Required permission: wiki:standard:create

Request body (JSON)

Required
Optional

If content includes YAML frontmatter (---\ntitle: ...\n---), those values take precedence over body params for title, description, and category. If content has no frontmatter, one is prepended automatically from the body params. Every stored revision is guaranteed to have frontmatter.

PUT /api/wiki/standards/:id

Edit a wiki standard. Uses baseRevisionId for conflict detection (returns 409 if outdated). CONTRIBUTOR-GATED: wiki:standard:* permissions come from the SiteContributor role, which you are granted by accepting the Contributor License Agreement (CLA). The account owner accepts it signed in, from their profile or the wiki; an API key cannot accept it. Until the account (for an API key, its OWNER) has accepted, this endpoint returns 403 no matter what the key was granted, and /api/whoami lists the permission under `dormant` with that step as its `remedy`.

Required permission: wiki:standard:edit

Parameters
NameInTypeDescription
idpathstringStandard UUID

Request body (JSON)

Required
Optional

baseRevisionId is required for conflict detection. If another user edited since your base, returns 409. Unknown fields are rejected — metadata changes go in the YAML frontmatter (title, description, category). tag_ids attaches tags to the NEW revision this edit creates, and it is the complete set for that revision — send the full list, not just the tags you are adding. Omitting tag_ids carries the base revision's tags forward unchanged; sending an empty array clears them. An edit that says nothing about tags therefore keeps them.

POST /api/wiki/standards/:id/revert/:revId

Revert a wiki standard to a previous revision. Creates a new revision carrying the old content AND the old tag set. CONTRIBUTOR-GATED: wiki:standard:* permissions come from the SiteContributor role, which you are granted by accepting the Contributor License Agreement (CLA). The account owner accepts it signed in, from their profile or the wiki; an API key cannot accept it. Until the account (for an API key, its OWNER) has accepted, this endpoint returns 403 no matter what the key was granted, and /api/whoami lists the permission under `dormant` with that step as its `remedy`.

Required permission: wiki:standard:edit

Parameters
NameInTypeDescription
idpathstringStandard UUID
revIdpathstringRevision UUID to revert to

GET /api/wiki/standards/search-users

Search users for wiki role assignment. Returns masked emails for privacy. Moderators only.

Required permission: wiki:standard:moderate

Parameters
NameInTypeDescription
queryquerystringSearch by name or email (min 2 chars). Accepts q as well. Under 2 chars returns an empty list, not an error.

GET /api/wiki/standards/:id/search-users

The same masked user directory as /standards/search-users, gated per standard: the standard's own moderators pass as well as global moderators. Used by the roles page so a per-standard moderator can find a successor to appoint.

Required permission: wiki:standard:moderate

Parameters
NameInTypeDescription
idpathstringStandard UUID
queryquerystringSearch by name or email (min 2 chars). Accepts q as well. Under 2 chars returns an empty list, not an error.

GET /api/wiki/standards/:id/roles

List wiki role assignments for a standard. The standard's own moderators pass as well as global moderators.

Required permission: wiki:standard:moderate

Parameters
NameInTypeDescription
idpathstringStandard UUID

POST /api/wiki/standards/:id/roles

Assign a wiki role (adopter or moderator) to a user for a specific standard. Allowed for a moderator OF THIS STANDARD (a per-standard wiki role) or for a holder of global wiki:standard:moderate — so a standard’s own moderator can always appoint a successor.

Required permission: wiki:standard:moderate

Parameters
NameInTypeDescription
idpathstringStandard UUID

Request body (JSON)

Required

Valid roles: adopter, moderator. User must be approved.

DELETE /api/wiki/standards/:id/roles/:roleId

Remove a wiki role assignment. Allowed for a moderator of this standard or a holder of global wiki:standard:moderate. Removing the last moderator of a standard is refused with 409; a moderator may resign while another remains.

Required permission: wiki:standard:moderate

Parameters
NameInTypeDescription
idpathstringStandard UUID
roleIdpathstringRole assignment UUID

POST /api/wiki/standards/:id/preview-adoption

Read-only dry-run of an adoption. Reports whether the revision would parse and adopt cleanly (isParseable, errors, elementCount, datasheetCount, resolvedCategoryPath, categoryPathError, isNew) without performing any writes. A revision that fails to parse returns 200 with isParseable:false, not an error.

Required permission: wiki:standard:adopt

Parameters
NameInTypeDescription
idpathstringStandard UUID

Request body (JSON)

Optional

sourceRevisionId is the revision being previewed; omit it to preview the latest revision (by revision_number).

POST /api/wiki/categories

Create a new wiki category in a library.

Required permission: wiki:category:create

Request body (JSON)

Required
Optional

PUT /api/wiki/categories/:id

Update a wiki category.

Required permission: wiki:category:update

Parameters
NameInTypeDescription
idpathstringCategory UUID

Request body (JSON)

Optional

parentId re-parents the category. Omitting it leaves the current parent alone — it is not a reset, so an update that means to keep the nesting does not need to resend it.

DELETE /api/wiki/categories/:id

Delete a wiki category. Standards filed directly in it become uncategorized. Sub-categories are NOT handled automatically — if the category has any, you must say what happens to them via childDisposition or the call is refused.

Required permission: wiki:category:delete

Parameters
NameInTypeDescription
idpathstringCategory UUID

Request body (JSON)

Optional

A category with NO sub-categories deletes with an empty body. With sub-categories, childDisposition is REQUIRED: the call returns 400 with requiresChildDisposition:true and the list of children, and that listing is the read to make the choice from. "reassign" re-parents them under childReassignTo, which must be a TOP-LEVEL category in the SAME library; "promote" makes them top-level; "cascade" DELETES the child categories and leaves their standards uncategorized (it destroys categories, never standards). Any other value is a 400. Deletion is permanent — there is no undo.

GET /api/wiki/search-content

Search the public wiki corpus and return matching clauses with their standard, address, and snippet. No auth, no project scope — the open-corpus twin of GET /api/standards/search-content. The response carries a search_event_id (uuid, or null when logging failed) purely so the browser can report a click back; API callers can ignore it.

Parameters
NameInTypeDescription
queryquerystringSearch text (required)
limitqueryintegerMax hits, 1-100 (default 20)

GET /api/wiki/standards/:librarySlug/:standardSlug/elements

Get the standard's current revision as STRUCTURED elements (address / content / toc_content / depth / attributes) rather than raw markdown, by running the shared adoption parser over the stored content. Same content the markdown read and the public wiki page already expose — this is the parsed form, so a client does not have to reimplement the parser to address individual clauses.

Parameters
NameInTypeDescription
librarySlugpathstringLibrary URL slug
standardSlugpathstringStandard URL slug

GET /api/wiki/standards/:librarySlug/:standardSlug/title

Get just { title } for a wiki standard. A deliberately tiny, cacheable read for callers that need the display name without pulling the whole document.

GET /api/wiki/standards/:standardId/revisions/:revId/tags

List the taxonomy tags attached to one wiki revision. Tags live on the REVISION, not the standard, so a tag set is only meaningful paired with the revision it was recorded against. CONTRIBUTOR-GATED: wiki:standard:* permissions come from the SiteContributor role, which you are granted by accepting the Contributor License Agreement (CLA). The account owner accepts it signed in, from their profile or the wiki; an API key cannot accept it. Until the account (for an API key, its OWNER) has accepted, this endpoint returns 403 no matter what the key was granted, and /api/whoami lists the permission under `dormant` with that step as its `remedy`.

Required permission: wiki:standard:read

GET /api/wiki/standards/:id/errata

Full errata audit trail for a wiki standard — active AND withdrawn, with their affected adopted revisions. Public.

Parameters
NameInTypeDescription
idpathstringWiki standard UUID

GET /api/wiki/errata/:errataId

Get one erratum in full, including every adopted revision and element address it affects. Public.

GET /api/wiki/adopted-revisions/:adoptedRevisionId/errata

ACTIVE errata for a single adopted revision — the banner hot path. Ask this before treating an adopted revision as correct: an empty array is the only evidence that no defect has been announced against it.

GET /api/wiki/moderation-log

Site-wide public moderation log, newest first. Each entry carries the action, the date, the reason category and — while the affected standard is still published — a link to it. The moderator, the free-text reason note and the removed content itself are never disclosed. Public, no auth.

Parameters
NameInTypeDescription
actionquerystringFilter to one action: archive, restore, revision_hide, revision_restore, adoption_revoke, adoption_restore, adoption_level_change, adoption_element_revoke, adoption_element_restore, adoption_scope_narrow, adoption_replacement_change, display_name_reset, errata_issued, errata_withdrawn, errata_extended, errata_linked_correction
reasonquerystringFilter to one reason category: spam, vandalism, test_content, copyvio (legacy), copyright_notice, suspected_copy, counter_notice, legal_compulsion, out_of_scope, merged_into, other
limitqueryintegerResults per page, 1-200 (default 50)
offsetqueryintegerOffset for pagination (default 0)

GET /api/wiki/moderation-log/:id

One public moderation log entry, addressed by the entry id the feed and the log page already print. Carries everything a feed entry carries plus `related` — every other public entry belonging to the same moderation matter, oldest first and including this one — so a withholding and the restoration that ended it read as one record. `scope.kind` says what the action reached — `clauses` (with a count and their positional addresses), `edition` (one adopted edition; the standard stays published), `standard` (an archive or restore) or `revision` (an editorial revision hidden or restored) — and is null for an action that reached none of the four. The clause addresses are withheld once the standard is no longer published. Returns 404 both for an unknown id and for an entry the site-wide feed does not show, so enumerating ids discloses nothing the feed does not. Public, no auth.

Parameters
NameInTypeDescription
idpathintegerModeration log entry id

GET /api/wiki/standards/:id/moderation-log

Public moderation log for one wiki standard. Returns 404 for any standard that is not publicly readable, including an archived one, so the endpoint cannot be used to confirm that a particular standard was removed; archived standards still appear in the site-wide feed with their identity withheld. Public, no auth.

Parameters
NameInTypeDescription
idpathstringWiki standard UUID
actionquerystringFilter to one action (see GET /moderation-log)
reasonquerystringFilter to one reason category
limitqueryintegerResults per page, 1-200 (default 50)
offsetqueryintegerOffset for pagination (default 0)

POST /api/wiki/standards/:id/direct-adopt

Adopt a revision, publishing it as the adopted (citable) version of the standard.

Required permission: wiki:standard:adopt

Request body (JSON)

Required

Use POST /standards/:id/preview-adoption first to confirm the revision parses. The response's adoption.syncStatus is 'queued': the standard's copy in the SynC library is updated in the background, usually within a few seconds, and retried if it fails. Requires the per-standard ADOPTER role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). A global permission grant alone is a 403.

POST /api/wiki/standards/:id/errata

Issue an erratum against one or more ADOPTED revisions of a standard. An erratum is a sibling annotation: it never edits the adopted revision or changes its content hash. This is the only correct way to announce that published content is wrong.

Required permission: wiki:errata:issue

Request body (JSON)

Required
Optional

Omitting element_address scopes the erratum to the whole adopted revision. Requires the per-standard ADOPTER role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). A global permission grant alone is a 403.

POST /api/wiki/standards/:id/errata/:errataId/revisions

Extend an existing erratum to additional adopted revisions once the defect is found to reach further back.

Required permission: wiki:errata:issue

Request body (JSON)

Required

Requires the per-standard ADOPTER role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). A global permission grant alone is a 403.

PATCH /api/wiki/standards/:id/errata/:errataId/correction

Point an erratum at the revision that corrects it, or clear that pointer by sending null. State change only — it does not withdraw the erratum.

Required permission: wiki:errata:issue

Request body (JSON)

Required

Requires the per-standard ADOPTER role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). A global permission grant alone is a 403.

POST /api/wiki/standards/:id/errata/:errataId/withdraw

Withdraw an erratum that should not have been issued. A state change, not a delete: the erratum stays in the audit trail and stops appearing as an active banner.

Required permission: wiki:errata:withdraw

Request body (JSON)

Required

Requires the per-standard ADOPTER role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). A global permission grant alone is a 403.

POST /api/wiki/standards/:id/archive

Archive (soft-delete) a wiki standard. 409 if it is already archived.

Required permission: wiki:standard:archive

Request body (JSON)

Required
Optional

Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

POST /api/wiki/standards/:id/restore

Restore an archived wiki standard. One permission gates both directions, and a reason is still recorded. 409 if the standard is not currently archived.

Required permission: wiki:standard:archive

Request body (JSON)

Required
Optional

Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

POST /api/wiki/standards/:id/title-reset

Reset a standard's title from a named source revision's frontmatter title, and record a title_reset entry in the public moderation log, which never repeats either title. 409 if the source revision is hidden or already carries the current title; 422 if it has no frontmatter title.

Required permission: wiki:standard:moderate

Request body (JSON)

Required
Optional

Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

POST /api/wiki/standards/:id/slug/retire

Retire a standard's current slug: move the standard to new_slug and reserve the old slug in its library. The old address answers 410 Gone and does not redirect. There is no undo. 409 if new_slug is taken or retired.

Required permission: wiki:standard:retire_slug

Request body (JSON)

Required
Optional

Admin tier only (WikiAdmin, SiteAdmin). Unlike the other moderation actions, a per-standard moderator role does not open this endpoint.

POST /api/wiki/standards/:id/revisions/:revId/hide

Hide a single wiki revision (soft moderation) without touching the rest of the history. If the hidden revision was current, the standard is repointed to the highest non-hidden revision. 409 if it is already hidden, or if the hidden revision is the source of the standard's current title (reset the title first).

Required permission: wiki:revision:hide

Request body (JSON)

Required
Optional

Returns { revision, currentRevisionRepointed, newCurrentRevisionId, activeAdoption, moderationLogEntry }. Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

POST /api/wiki/standards/:id/revisions/:revId/restore

Un-hide a hidden wiki revision, auto-promoting current_revision_id forward to the highest non-hidden revision.

Required permission: wiki:revision:hide

Request body (JSON)

Required
Optional

Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

POST /api/wiki/standards/:id/adopted/:adoptedRevId/revoke

Revoke an adopted revision. The snapshot CONTENT and its content_hash are never touched — only the revoked state — so the immutability promise holds for anything already cited. If the revoked edition was the standard's current adopted revision, the pointer moves to the most recent surviving edition, or to null when none remain. 409 if it is already revoked or was never published (status review/cancelled); 404 if the adoption belongs to a different standard.

Required permission: wiki:adoption:revoke

Request body (JSON)

Required
Optional

Returns { adoptedRevision, currentAdoptedRevisionRepointed, newCurrentAdoptedRevisionId, moderationLogEntry }. Revoking does NOT hide the source wiki revision — that is a separate action on a separate permission. Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

POST /api/wiki/standards/:id/adopted/:adoptedRevId/restore

Restore a revoked adopted revision. One permission gates both directions, and a reason is still recorded. The standard's adopted pointer is promoted FORWARD only, never backward. 409 if it is not currently revoked.

Required permission: wiki:adoption:revoke

Request body (JSON)

Required
Optional

Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

POST /api/wiki/standards/:id/adopted/:adoptedRevId/replacement

Mark the adopted edition that REPLACES a revoked one, starting the days-after-replacement clock on its open revocation window. The replacement is a moderator judgment and is never auto-detected: it may be an OLDER surviving edition, and re-marking overwrites the previous mark. 400 if the id is missing or names the revoked edition itself; 404 if either id is unknown or belongs to another standard, or if that edition has no open revocation window; 409 if the proposed replacement was never published (status review/cancelled) or is itself revoked.

Required permission: wiki:adoption:revoke

Request body (JSON)

Required

Returns { effect, deadlines, eventType }. `deadlines` are derived from config/moderationPolicy.js on every read, so changing a policy number moves every open deadline. Marking notifies the project:admin holders of affected projects that an upgrade now clears the restriction, and starts the clock after which level 2 applies. Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

GET /api/wiki/moderation/worklist

Open moderation matters, flagged items first and the oldest matter leading each tier. Each row carries the standard, the scope, the address of the held clause, how long it has been open, and which signals have fired: `changed` (the held text moved since a moderator last looked), `unlocatable` (the clause could not be found in the saved text) and `escalated` (the matter passed the 90-day mark and calls for an explicit lift or affirm). A signal is advisory: it never permits an adoption and never lifts a hold. Carries NO clause text. Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

Required permission: wiki:adoption:revoke

Parameters
NameInTypeDescription
statequerystring'open' (default), 'resolved' or 'all'
standardIdquerystringRestrict to one standard (UUID)
limitqueryintegerPage size, 1-500 (default 100)
offsetqueryintegerRows to skip (default 0)

GET /api/wiki/moderation/worklist/:itemId

One moderation matter, whole: the worklist row as the list serves it, the hold it hangs off with its standard, adopted edition and noticed revision, every clause identity the hold covers with whether each has been cleared and where its hold stops (the release point, when a moderator has recorded one), the hold's own 30/90 window measured from the day it opened, the adopted editions a release point could name, a record of which parties were notified and when (counts only, never a recipient), and the public-register rows this hold produced. While the `changed` signal stands it also carries `texts`: the clause text a moderator last reviewed beside the text now at that slot. THIS IS THE ONLY ENDPOINT THAT SERVES HELD CLAUSE TEXT, and it serves it only to a moderator of that standard — deciding whether held text has been rewritten is not possible without both. `texts` is null on any matter whose held text has not moved. 404 when no such item exists. Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

Required permission: wiki:adoption:revoke

Parameters
NameInTypeDescription
itemIdpathintegerWorklist item ID

GET /api/wiki/moderation/revoked-editions

The revision-level revocation register: adopted editions revoked outright, oldest first, each with the reason, the level in force, the 30/90 window running toward level 2, the replacement edition if a moderator has marked one, and the restore date if it was restored. `state=open` (default) lists editions still revoked; `state=all` includes restored ones. DISTINCT FROM THE WORKLIST: a revoked edition is withdrawn whole, while a hold withholds named clauses without revoking anything and has no window at all. Carries NO clause text. Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

Required permission: wiki:adoption:revoke

Parameters
NameInTypeDescription
statequerystring'open' (default) or 'all'
limitqueryintegerPage size, 1-500 (default 100)
offsetqueryintegerRows to skip (default 0)

GET /api/wiki/moderation/register

Every row of the wiki moderation log, newest first — the moderator's own view of the table the public register projects. It carries the three things the public register withholds: the real actor (the moderator who performed the action, resolved to a name), the private reason note, and the target even where the standard is no longer published. Rows the public register never shows are listed here too, marked `isPublic: false`, because a row the projection drops must not vanish from the one place a moderator can read it. A reader-filed `attribution_report` row names NO filer: its actor is never resolved, on any row, to anyone. `entryUrl` is the public permalink and is null on a row the public register does not carry; `identityWithheldPublicly` says the register shows the row without naming its standard. Served alongside the rows: `total`, `notPublic` and `withNote` over the whole filtered set, plus the two filter vocabularies (`actions`, `standards`). NOT the public register — that is GET /api/wiki/moderation-log, which is unauthenticated and carries none of these fields. The path is `/moderation/register` rather than `/moderation/log` because tool names flatten punctuation, and two endpoints with opposite disclosure rules must not derive one name. Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

Required permission: wiki:adoption:revoke

Parameters
NameInTypeDescription
actionquerystringRestrict to one wiki_moderation_action value. Accepts every value the enum carries, including `attribution_report`, which the public register excludes.
standardIdquerystringRestrict to one standard (UUID)
limitqueryintegerPage size, 1-100 (default 25)
offsetqueryintegerRows to skip (default 0)

POST /api/wiki/moderation/log/:id/statement

Publish SynC's own statement on a public moderation log entry, or revise the one that stands. Body: `{ text }`. The statement appears on the public entry page under SynC's name, is optional and never expected, and may be revised or withdrawn later; every version is kept, so the statement table is its own change record and no row is written to the moderation log for a statement change. NOT the private reason note: that column is written for moderators and is never published at any level, and a statement that merely repeats it is refused. 400 when the text is blank, over 2000 characters, or repeats the note; 404 when no such entry exists; 409 when the entry is not one the public register carries, so there is no page for a statement to appear on. Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

Required permission: wiki:adoption:revoke

Parameters
NameInTypeDescription
idpathintegerModeration log entry ID
textbodystringThe statement, 1-2000 characters

DELETE /api/wiki/moderation/log/:id/statement

Withdraw the statement that stands on a moderation log entry. The text comes off the public entry page and is not shown again; the page then records that SynC published a statement and withdrew it, with both dates. Nothing is deleted — a statement that stood in public and then vanished without trace is the silent edit the version history exists to prevent. 404 when no such entry exists; 409 when no statement stands to withdraw. Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

Required permission: wiki:adoption:revoke

Parameters
NameInTypeDescription
idpathintegerModeration log entry ID

POST /api/wiki/moderation/worklist/:itemId/resolve

Resolve one open matter, by one of three moves. `lift` clears the hold on that clause — the ONLY thing that lifts a hold; editing the clause does not — resolves the item, and ends the whole action when it was the last clause held, at which point adoption of the standard is permitted again. `affirm` says the hold stands: it advances the changed-text reference point so the same words never flag twice, clears the signal, and LEAVES THE ITEM OPEN, because an affirmed hold is still an open matter. `release` records that the clause is clear FROM A GIVEN ADOPTED EDITION ONWARD while earlier editions stay withheld: that edition and every later one render it, the wiki head renders it, a project holding a released edition may publish again, and the upgrade panel offers it as the way out. It leaves the item OPEN for the same reason `affirm` does — earlier editions are still withheld and the matter is still open. Sending `release` with no `releasedFromAdoptedRevisionId` WITHDRAWS the release point, so every edition carrying the clause is withheld again; that is the path for a later edition that reintroduces the noticed text. 404 no such item, or no such adopted revision; 409 the item is already resolved, the hold has already ended, the clause was already lifted, the edition belongs to another standard, or the release point would sit at or before the edition the withheld text first appeared in — which is a lift, and must go through one.

Required permission: wiki:adoption:revoke

Request body (JSON)

Required
Optional

Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

POST /api/wiki/moderation/worklist/:itemId/counter-notice

Record a §512(g)(2) counter-notice on one moderation matter and start the statutory window. The moderator transcribes it from the designated agent’s mailbox: there is no public counter-notice form. The window is counted from RECEIPT, never from the forwarding, so a slow forwarding cannot extend the period the material stays withheld; the server computes business day 10 (`restore_due_at`, when the sweep restores) and business day 14 (`restore_deadline_at`, the outer bound) and STAMPS them, and they are never recomputed afterwards. Business days are Monday to Friday with no holiday calendar. The counter-notice’s text and the sender’s name are NOT stored — only the receipt date and the identifier the e-mail is filed under. Nothing here is published: the public register carries the restoration when one happens and nothing about the counter-notice itself. 400 a future date, a blank or over-long reference, or a forwarding dated before the receipt; 404 no such item; 409 a counter-notice window is already running on this matter, or the hold has already ended. Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

Required permission: wiki:adoption:revoke

Parameters
NameInTypeDescription
itemIdpathintegerWorklist item ID

Request body (JSON)

Required
Optional

Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

POST /api/wiki/moderation/worklist/:itemId/counter-notice/forwarded

Record that the counter-notice was forwarded to the complainant, as §512(g)(2)(B) requires. An unrecorded forwarding is indistinguishable from none, which is why it is a stored date rather than an inference. It does NOT move the window, which is counted from receipt. Recorded once and not overwritten: the date is evidence about a statutory obligation. Still available after a court action has stopped the window, because that obligation does not lapse because the complainant filed. 400 a future date, or one before the receipt; 404 no counter-notice on this matter; 409 the forwarding is already recorded, or the window ended in a restoration. Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

Required permission: wiki:adoption:revoke

Parameters
NameInTypeDescription
itemIdpathintegerWorklist item ID

Request body (JSON)

Required

Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

POST /api/wiki/moderation/worklist/:itemId/counter-notice/court-action

Record that the complainant has told SynC’s designated agent an action has been filed seeking to restrain the material. THE ONLY THING THAT STOPS THE COUNTER-NOTICE WINDOW: the sweep does not restore, and the hold stands. It does NOT end the matter — affirm, release, lift and restore all stay available afterwards — and nothing about the court action is ever published. Only the court and docket, or the identifier the notice is filed under, is stored. 400 a future date, a blank reference, or a date before the receipt; 404 no counter-notice on this matter; 409 a court action is already recorded, or the window ended in a restoration. Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

Required permission: wiki:adoption:revoke

Parameters
NameInTypeDescription
itemIdpathintegerWorklist item ID

Request body (JSON)

Required

Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

POST /api/wiki/moderation/worklist/:itemId/counter-notice/restore

Restore the held material before the counter-notice window runs out. The same whole-action restore the nightly sweep performs at the end of the window, taken earlier by a moderator: every held clause is restored, the hold ends, every open matter on it resolves, and the release notice goes to the parties the hold notice reached. Filed in the public register under `counter_notice`, which the projection labels "Counter-notification received" — the only indication a public reader gets of why the material came back. Refused when a court action stopped the window: restoring anyway is the ordinary POST /moderation/element-actions/:actionId/restore, which says in the register that a moderator lifted the hold rather than that a statutory window ran out. 404 no counter-notice on this matter; 409 a court action stopped the window, the window has already ended, or the hold has already been restored. Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

Required permission: wiki:adoption:revoke

Parameters
NameInTypeDescription
itemIdpathintegerWorklist item ID

Request body (JSON)

Optional

Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

GET /api/wiki/standards/:id/adopted/:revNum/elements

The selectable clauses of one adopted edition: each clause identity and the address it sits at, in document order. Carries NO clause text — the text is read from GET /standards/:id/adopted/:revNum; this index exists to tie a rendered clause to the identity a hold is keyed on. 404 when the edition is unknown or has no synced SynC revision (adoption syncs best-effort, so an unsynced edition is a real state in which no clause can be identified). Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

Required permission: wiki:adoption:revoke

Parameters
NameInTypeDescription
idpathstringStandard UUID
revNumpathintegerAdopted revision number

POST /api/wiki/moderation/element-actions

Open a hold on one or more clauses of an adopted edition, or on a whole standard. Records what the NOTICE identifies — SynC follows a notice and neither assigns blame nor judges merits — so `noticedRevisionId` is required for every held matter and is never defaulted, and `scope` is required and explicit: an empty clause list is never read as a whole-standard hold. The hold is keyed on the clause identity and follows that slot forward into every later edition until a moderator lifts it. 404 an unknown edition, or a clause absent from the named edition; 409 an edition that was never published, or one already revoked at revision level and named without `narrowFrom`.

Required permission: wiki:adoption:revoke

Request body (JSON)

Required
Optional

Returns { action, identities, members, worklist, logEntry, narrowedFromEffectId }. Every open hold is on the moderator worklist from the moment it opens. Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

POST /api/wiki/moderation/element-actions/:actionId/restore

Lift a hold: one restore, the whole set, both scopes. The action ends, every clause still held is cleared and every open worklist item is resolved, in one transaction. The evidentiary member rows are kept — they record what was noticed where, which a later dispute needs whether or not the hold still stands. 404 an unknown action; 409 one already restored.

Required permission: wiki:adoption:revoke

Request body (JSON)

Optional

Requires the per-standard MODERATOR role in addition to the permission (SiteAdmin bypasses via wiki:standard:moderate). Every moderation action is written to the moderation log with its reason — there is no silent form of this call.

POST /api/wiki/standards/:standardId/revisions/:revId/tag-only-revision

Change a standard's tags by appending a NEW revision that carries the parent's content and content hash unchanged, with the new tag set attached. The wiki has no working-copy concept, so this is the ONLY correct way to change tags: writing tags onto an existing revision would edit a record that has already been read and cited. CONTRIBUTOR-GATED: wiki:standard:* permissions come from the SiteContributor role, which you are granted by accepting the Contributor License Agreement (CLA). The account owner accepts it signed in, from their profile or the wiki; an API key cannot accept it. Until the account (for an API key, its OWNER) has accepted, this endpoint returns 403 no matter what the key was granted, and /api/whoami lists the permission under `dormant` with that step as its `remedy`.

Required permission: wiki:standard:edit

Request body (JSON)

Required

The array REPLACES the tag set rather than adding to it, so send every tag the revision should end up with, including ones it already has. An empty array clears all tags. :revId is the PARENT revision the new revision descends from — normally the standard's current revision.

POST /api/wiki/standards/tags/suggest

Ask the tagging model to suggest taxonomy tags for wiki standard content. Returns { tags: [{ id, label, confidence }] } — suggestions only; nothing is attached until you call the tag-only-revision endpoint. Session only: an API key gets 403, because an API key can't trigger SynC's AI. CONTRIBUTOR-GATED: wiki:standard:* permissions come from the SiteContributor role, which you are granted by accepting the Contributor License Agreement (CLA). The account owner accepts it signed in, from their profile or the wiki; an API key cannot accept it. Until the account (for an API key, its OWNER) has accepted, this endpoint returns 403 no matter what the key was granted, and /api/whoami lists the permission under `dormant` with that step as its `remedy`.

Required permission: wiki:standard:edit

Request body (JSON)

Required
Optional

POST /api/wiki/revisions/:revisionId/report-attribution

Report a contribution-attribution problem on a wiki revision (impersonation, a wrong employer byline, an undisclosed conflict). Any authenticated reader may report. A hidden or non-existent revision returns 404 rather than confirming it exists.

Request body (JSON)

Required

POST /api/wiki/standards/:librarySlug/:standardSlug/import-to-new-project

Create a placeholder project from a wiki standard in one atomic call: mirrors the standard's category into project scope, attaches the ADOPTED revision to the new project's draft, and returns the deep link to its datasheet. The signed-in half of the wiki "use this standard" call to action. Any signed-in account may call it, company or no company: the company is required at first publish or first distribution, not at import.

Request body (JSON)

Required
Optional

Returns { success, projectId, standardId, datasheetUrl }. Generate a fresh idempotency_key per intended import and REUSE it on retry — that is what stops a network retry from creating a duplicate project.