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.

Parameters
NameInTypeDescription
idpathstringStandard UUID

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

Get a specific adopted revision by revision number.

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).

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.

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).

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.

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/roles

List wiki role assignments for a standard.

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.

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.

Required permission: wiki:standard:moderate

Parameters
NameInTypeDescription
idpathstringStandard UUID
roleIdpathstringRole assignment UUID

POST /api/wiki/standards/:id/cancel-review

Cancel an in-progress adoption review. Only the review starter or a moderator can cancel.

Required permission: wiki:standard:adopt

Parameters
NameInTypeDescription
idpathstringStandard 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.

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.

POST /api/wiki/standards/:id/review

Start an adoption review by selecting a revision as the candidate snapshot. Creates the review record that POST /standards/:id/adopt then adopts; cancel it with POST /standards/:id/cancel-review.

Required permission: wiki:standard:adopt

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/adopt

Adopt a revision that is already under review, publishing it as the adopted (citable) version of the standard.

Required permission: wiki:standard:adopt

Request body (JSON)

Required

adoptedRevisionId is the id of the adoption record from POST /standards/:id/review, NOT the wiki revision id you passed to it. 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/direct-adopt

Adopt a revision in one step, skipping the review record. Same effect and same authority as review + adopt.

Required permission: wiki:standard:adopt

Request body (JSON)

Required

Use POST /standards/:id/preview-adoption first to confirm the revision parses. 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/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.

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/: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.

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.

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.

Required permission: project:create

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.