Skip to main content

API Changelog

Changes to the Align Public API v1, its webhooks, and the MCP server, newest first. Each change is marked Added, Changed, Fixed or Removed. Read the Changed and Removed items carefully: they can affect an existing integration.

Convention for contributors: add a new ## YYYY-MM-DD section at the top, dated by when the change shipped, with a short description written for API users. Do not reference internal ticket numbers.


2026-11-10​

Changed: code_quality.analysis_completed is not delivered to Marketplace apps​

  • An event only a workspace's staff may see is delivered only to webhook subscriptions the workspace created: one an admin created in Align, or one created with a workspace API key. Today that is code_quality.analysis_completed; an internal note's entry.commented was already delivered to no subscription.
  • It is not delivered to a subscription created with the key of an app installed from the Marketplace, or whose destinationUrl such a key last changed, whether the subscription names the event or *. The app still receives every other event it subscribes to. Delivery is checked when the event is queued and again when it is sent. A subscription that an admin points somewhere else in Align is the workspace's again.
  • Subscriptions created before this change are treated as the workspace's own.
  • The payload: projectId, sonarProjectKey, branch (the branch analysed; main when SonarQube named none), branchType (BRANCH or PULL_REQUEST), pullRequest (for a pull request), gateStatus and previousGateStatus (OK, WARN, ERROR or NONE; previousGateStatus is null when Align knew no gate for that branch yet), taskId, analysedAt, revision and source. source says how Align heard of the analysis: webhook (SonarQube's webhook reported it, and taskId is its task) or sweep (Align's own hourly or on-demand refresh found an analysis no webhook reported, and taskId is null). analysedAt and revision can be null. One analysis is announced at most once by each path, so a consumer that acts once per analysis keys it on the project, the branch or pull request, and analysedAt.

Changed: get_code_quality answers a release with the release check's own decision​

  • With releaseId, the release block is now the answer the release page shows and the release check applies when the release is marked shipped, so the three cannot disagree. It was the project's main branch, compared with the release's version.
  • release.basis is release_check (it was main_branch). New fields: state (passed, failed, warn, missing or stale; null when the project is not bound or SonarQube is not connected), message (the release check's sentence), branchReason, analysedAt, versionMatch (matched, different or unknown), stale, staleReason, conditions, canBlock, mode (the project's release checks), blocksShipping and url. branch is now the branch the gate was read from; it was always null.
  • versionMatches and analysedVersion keep their meaning, but versions are now compared as the release check compares them: a leading v and letter case are ignored, so release V1.4.0 matches an analysis of 1.4.0.
  • An analysis nothing has refreshed for 24 hours is stale (staleReason: "not_refreshed"), as on the release page, and never blocks. Before, only an analysis Align had marked stale was.
  • For a release, summary is the release check's sentence, and says when the gate blocks the release.

Changed: project responses no longer include two code-quality settings​

  • GET /api/v1/projects/{id}, GET /api/v1/projects, and the project returned by POST and PATCH included qualityGateCanBlock and sonarqubeSuggestMode, which are not in the API reference. They are no longer returned to any key. They were already not writable with a key.
  • MCP's get_project and list_projects include them only for staff of the project's workspace, by the role held there; a client, user or viewer does not get them.

Added: the MCP tool get_code_quality​

  • get_code_quality reads a project's SonarQube code quality as Align last stored it: the quality gate's status (green when it passes) with its failingConditions, the key measures, when the main branch was last analysed, and the gates of other branches and pull requests. Pass releaseId for a release (answered from the main branch, with the release's version and versionMatches), or entryId for the SonarQube issues linked to an entry and their last-known status. It is read-only and never sends anything to SonarQube.
  • Only the workspace's staff can use it, by the role they hold in that workspace. A client, user or viewer gets staff_only, whatever they ask for. A project that is not bound answers status: "not_bound", and a workspace without SonarQube answers status: "not_connected".
  • Project-scoped keys can call it for their own project.
  • While Forward Rise has paused the SonarQube app for every workspace, the answer is the last stored one, with stale: true and staleReason: "paused".

Added: the SonarQube quality gate in release checks​

  • ReleaseOpenItem.kind has a new value, quality_gate. It can appear in blocking or warnings wherever release checks are reported: the 409 release_checks_open body of PATCH /api/v1/releases/{id} and POST /api/v1/projects/{id}/releases, and releaseChecks on a release they write. MCP's update_release reports it the same way.
  • It appears only for a project bound to a SonarQube project, in a workspace where SonarQube is connected. A passing gate adds nothing.
  • A failing quality gate is a warning. It is blocking only when the project has turned on SonarQube quality gate can block in Align and its release checks are block; overrideReason then overrides it as it does any other blocking item. That setting is not writable with an API key.
  • An analysis that is out of date, or missing, is always a warning. So is any gate while Forward Rise has paused the SonarQube app: Align can't vouch for a gate it is not reading, so it never blocks then; message says the app is paused.
  • message names the SonarQube project, the failing conditions and the analysis that was read; for a failing gate, count is the number of failing conditions. That detail is shown only when the key's creator is staff of the project's workspace, by the role they hold there. For any other key a quality_gate warning is left out, and a blocking one reads "A check that only this workspace's staff can see is failing. Ask them about it." with count 1. The release is still blocked.

2026-11-09​

Changed: marking a release shipped meets the project's release checks​

  • Each project now has a release checks setting: block, warn or off. A project with no setting uses its default: block for a project owned by a client of its workspace, warn for an internal project. Admins and managers change it on the project's settings page; it is not writable with an API key.
  • PATCH /api/v1/releases/{id} that moves a release into released or completed from any other status, and POST /api/v1/projects/{id}/releases that creates one already released or completed, now meet those checks. Saving a release that is already shipped is not judged again.
  • In block mode the request answers 409 (reason: "release_checks_open") while anything blocking is open on the release: its approval workflow (pending or rejected — a release with no approval of its own is under the project's default release workflow), legacy approval gates, entries still awaiting the client's approval, or a cost sign-off that was submitted and not finished (an entry's or the release's committed cost). Nothing is written. The body lists blocking and warnings; each item has kind, count, message and up to ten refs.
  • Unfinished dependencies, a release it depends on that has not shipped, open checklist items and open bugs are only ever warnings.
  • In warn mode, and in block mode with nothing blocking, the write goes through and the release returned carries releaseChecks (mode, overridden, blocking, warnings). In off mode nothing changes.
  • Added: overrideReason on both release bodies. It overrides a block when the key's creator is an admin of the key's workspace (by the role they hold there) or a platform operator, and the override is recorded in the workspace's audit log with the reason and what was open. A blank reason answers 400 (reason: "override_reason_required"); any other creator gets 403 (reason: "override_not_allowed"). It is not stored on the release.
  • MCP: update_release meets the same checks and takes overrideReason (honoured for an admin of the workspace). Changing a release's status through update_release now needs an admin or manager of the workspace, as in the app; developers, testers and the other write roles can still change a release's name, description and dates.

Changed: a key stops working when the person who created it can no longer act in its workspace​

  • A key acts as the person who created it: what it writes is theirs. Every request made with a key — Public API, SCIM and MCP — now answers 401 (reason: "key_revoked") once that person's account is suspended or archived, or they are no longer an active member of the key's workspace (removed from it, or deprovisioned there by your identity provider). A platform operator's key follows the operator's account the same way.
  • When that happens from now on, the key is also revoked, so it stays revoked if the person is reactivated or added back. Mint a new key.
  • The same applies to a key created, or an MCP authorization granted, by the founder of a workspace that signed up on its own and never verified its email address: that account can no longer sign in, so the key answers 401 (reason: "key_revoked") and the authorization stops working, with no new token issued on refresh.
  • Keys whose creator had already left, or been suspended, before this change are refused from now on but are not revoked yet. Until Align revokes them, such a key works again if its creator regains access. Mint a new key rather than rely on that.
  • This includes organization-scoped keys, Marketplace installation keys and SCIM tokens. If the person who installed an app or created your SCIM token leaves the workspace, a current admin re-issues the installation's key from the installed app, or mints a new SCIM token.

Changed: webhooks are delivered only to public https destinations​

  • POST and PATCH /api/v1/webhooks now refuse (400 validation_error) a destinationUrl that is not an https:// URL on a public host: a loopback, private, link-local or otherwise non-public address, written in any form, localhost, *.internal, or a name that resolves to such an address. Before, only the https:// prefix was checked.
  • Every delivery is checked again when it is sent. A subscription that no longer passes is not sent anything; each delivery is dead-lettered with "Destination not allowed" and not retried. Edit the destinationUrl to resume.
  • Redirects are no longer followed. A 3xx response is a failed delivery, recorded and not retried.
  • Your endpoint's response body is no longer stored, and was never part of the API.
  • POST /api/v1/webhooks/{id}/test now needs write:webhook instead of read:webhook. Its deliveryError is now also present for a 3xx or 4xx response.

2026-11-08​

Changed: internal notes are never delivered to webhooks​

  • entry.commented is no longer delivered for an internal note, to any webhook subscription: one created by a workspace admin, by an API key (POST /api/v1/webhooks) or by a marketplace app. Until now a subscription received internal notes too, with isInternal: true and the note's first 200 characters in bodyPreview.
  • A delivery already queued for a comment that is made internal before it is sent is not sent either.
  • A delivered entry.commented therefore always has isInternal: false. The field stays in the payload.
  • Comments the client can see are delivered exactly as before.

Changed: the audit trail leaves out internal notes for a key whose creator cannot read them​

  • GET /api/v1/audit-events no longer returns the events about an internal note (they hold the note, text included) unless the key's creator can read internal notes in the key's workspace: a platform operator, or an active member whose role there is a staff role. This is the rule GET /api/v1/entries/{id}/comments already uses.
  • For any other key those events are left out, and total counts only the events returned.

Changed: wiki pages keep only a short list of HTML tags​

  • Wiki content written with POST /api/v1/projects/{id}/wiki-pages or PATCH /api/v1/wiki-pages/{id} is now saved with its raw HTML limited. Outside code spans and fenced code blocks, <br>, <sub>, <sup>, <kbd>, <mark>, <details> and <summary> are kept, without attributes (<details> may keep open). Any other tag, an HTML comment or anything <!…> is saved escaped, so <div> is stored as &lt;div&gt; and shows as the text that was sent.
  • A < that does not start a tag, as in a < b, is saved as sent. Code spans and fenced blocks are saved as sent.
  • The content a page returns is what was saved. Pages saved before this change are not rewritten; Align shows their other HTML as text.

Changed: a key deletes someone else's comment only when its creator is an admin of the workspace​

  • DELETE /api/v1/comments/{id} now answers 403 (reason: "forbidden") for a comment someone else wrote, unless the key's creator is an admin of the key's workspace (by the role they hold there) or a platform operator. Until now any key with delete:comment could delete any comment in its workspace, including a key created by a client.
  • A key still deletes its creator's own comments, as before.
  • A refused request deletes nothing.
  • An internal note the key's creator cannot read still answers 404, as a missing comment does.
  • This is the rule Align itself applies when someone deletes a comment in the app.

Changed: only a key whose creator can read internal notes can write one​

  • POST /api/v1/entries/{id}/comments with isInternal set, and PATCH /api/v1/comments/{id} setting isInternal, now answer 403 (reason: "forbidden") unless the key's creator can read internal notes in the key's workspace: a platform operator, or an active member whose role there is a staff role (admin, manager, developer, tester, tech lead, product owner or DevOps engineer). Until now any key with write:comment could post an internal note, including a key created by a client, a portal user or a viewer, whose own GET then hid it.
  • A refused request posts nothing: the comment is not posted as a visible comment instead, and a refused PATCH leaves the comment as it was.
  • Comments without isInternal (or with it null) are unchanged, as is everything else these operations do.
  • The rule is the one GET /api/v1/entries/{id}/comments uses to decide who sees internal notes, so a key can now write an internal note exactly when it can read one back.

2026-11-07​

Removed: fields that record who did something, from the comment, attachment and release write bodies​

  • POST /api/v1/entries/{id}/comments and PATCH /api/v1/comments/{id} no longer take isAiGenerated. A comment posted with an API key is its creator's and is not AI-generated, as a comment posted in Align is; PATCH no longer changes whether a comment reads as AI-written.
  • POST /api/v1/entries/{id}/attachments no longer takes isAiGenerated, linkedByUserId or removedByUserId. The uploader is the key's creator, as before.
  • PATCH /api/v1/releases/{id} no longer takes costUpdatedById; the one Align recorded stays. POST /api/v1/projects/{id}/releases already ignored it.
  • A request that still sends one of these fields is not refused, on PATCH as on POST: the field is ignored and the rest of the request is applied. PATCH /api/v1/comments/{id} with authorId, which answered 400, now ignores it too, and a PATCH left with nothing to change returns the comment as it is.
  • These fields are still returned on comments, attachments and releases.
  • SDKs (still 1.0.0): entries.createComment and comments.update no longer take isAiGenerated. TypeScript drops it from the body types; Python refuses it before sending, as it does any field an operation does not take.

2026-10-28​

Removed: approvalStatus and costApprovalStatus from the entry write bodies​

  • POST /api/v1/projects/{id}/entries no longer takes approvalStatus or costApprovalStatus; a value sent is ignored, and a new entry starts as approved with its cost at draft, as before when the fields were left out.
  • PATCH /api/v1/entries/{id} now answers 400 when either field is in the body. An approval is recorded by the approval flow (in Align, or through the MCP cost approval tools), which also records who decided; the API could set the status with nobody on record.
  • Both fields are still returned on every entry.

Changed: project updates follow the same rules as in Align​

  • PATCH /api/v1/projects/{id} now refuses, as the app does, a programId that is not a program of the project's workspace (400), a kind other than software or business (400), and a change to committedCost once billing has locked it (409, reason: "committed_cost_locked"; use the change-order flow in Align).

Fixed: refreshing an authorisation that was granted no scopes​

  • An MCP authorisation granted before 2026-10-24 with no scopes stayed unusable after every refresh. A refresh now grants align:read, which is what the consent screen showed, so the connection works without re-authorising.

Added: delivery of the time, agreement, code, user and project member events​

  • Subscriptions now receive time.logged, time.updated, time.deleted, time.submitted, time.approved, time.rejected, time.unlocked, agreement.signed, pr.merged and commit.linked. These were accepted and recorded but never delivered, because Align could not work out which workspace they belonged to.
  • The public API now emits, and Align delivers, user.invited, user.linked, user.updated and user.bulk_invited from POST /api/v1/users/invite, POST /api/v1/users/bulk-invite and PATCH /api/v1/users/{id}, and project_member.added, project_member.updated and project_member.removed from the /api/v1/projects/{id}/members routes.
  • user.invited for an emailed invitation carries userId: null, invitationId and pending: true; a user provisioned directly carries its userId and pending: false.
  • x-align-events-not-yet-delivered now lists six names: integration_link.created, integration_link.updated, subscription.updated, pi_board.updated, pi_board.published and pi_board.deleted.
  • See Webhooks for the payload fields of each family.

2026-10-23​

Changed: three new entry statuses​

  • Entry status can now also be blocked, testing and done. In workflow order the statuses are open, assigned, in_progress, blocked, testing, deployed, done, solved. done follows deployed; solved means closed without a deploy.
  • The new values appear in entry responses, are accepted by POST /api/v1/projects/{id}/entries and PATCH /api/v1/entries/{id}, and appear in entry.status_changed webhook payloads. If your integration checks status against a fixed list, add the new values.
  • Align now moves entries to testing when they are deployed to a testing or staging environment, and closes verified entries as done.

Fixed: the OpenAPI spec and both SDKs match the API​

  • Every operation in openapi.json now has an operationId, names the permission it checks (x-required-permission), and marks the Illumera add-on (x-requires-addon) and time-tracking (x-requires-feature) gates. Every operation documents 423 suspended; time-tracking operations document 402 feature_disabled.
  • The spec now describes what the server returns: comments have content (not body), time entries have their real columns (notes, invoicedAt, the approval fields; there is no invoiced flag), approve sets locked, time and cost summaries return minute totals, invites return created/linked/updated with pending, bulk invites return a summary, and member, wiki, snapshot, search, audit and agreement shapes and enums are corrected.
  • Added to the spec and both SDKs: GET /api/v1/time-entries, GET /api/v1/projects/{id}/releases/{releaseId}/time-summary, GET /api/v1/users/{id}/time-summary and POST /api/v1/ci/test-runs (permission write:test_run).
  • Removed from the SDKs: comments.retrieve and attachments.retrieve, which called routes that do not exist.
  • SDK changes (still 1.0.0, not yet published): the default base URL is https://app.alignsoft.us/api/v1; bodies and parameters are typed from the spec (createEntry needs type, title and description; timeEntries.reject needs reason; projects.addMember takes the user id in the body); a POST is retried only on 429 or with an idempotency key; AlignApiError parses non-JSON and legacy { error } bodies and reads retryAfter from details or the Retry-After header; releases.getEvidence returns the signature headers.
  • CI now fails when either SDK drifts from the spec: method, path, parameters, body fields and enums are compared in both directions.

Fixed: request handling​

  • POST /api/v1/users/bulk-invite honours a top-level sendInvite: false. An item's own sendInvite still wins.
  • PATCH /api/v1/projects/{id}/members/{userId} with roleOverride: null now removes the override.
  • Time-entry lists and summaries accept startDate / endDate and, as deprecated aliases, workDateFrom / workDateTo (what the SDKs used to send, and which were ignored).
  • GET /api/v1/integration-links now filters by alignEntityId.
  • The addon_required, unknown_event_names, unlock insufficient_role and webhook-test rate_limit errors now use the { reason, message, details } envelope. The old top-level fields are still sent.
  • Keys can now be given write:wiki, delete:wiki and delete:time_entry, which those routes already checked but the key editor did not offer. The organisation default includes them.

Changed: webhook vocabulary​

  • Added project.transfer_initiated and project.transferred.
  • Thirteen events that nothing emits yet are marked "not yet delivered" in the docs and listed in the spec's x-align-events-not-yet-delivered.

2026-10-22​

Fixed: agreements scoped to your organisation​

  • GET /api/v1/projects/{id}/agreements could include an agreement from another organisation that pointed at the same project ID. It now returns only your organisation's agreements.

2026-10-20​

  • The OAuth consent screen now lists the organisations you belong to where MCP is turned on, and you choose which one to authorise. It defaults to the workspace you are working in. Before, it always authorised your original organisation. See MCP Integration.

Changed: suspended and archived users lose OAuth access​

  • A suspended or archived user can no longer complete OAuth authorization or refresh a token (400 invalid_grant, "User account is not active"), and their existing access tokens stop working.
  • Invitation emails sent by POST /api/v1/users/invite and POST /api/v1/users/bulk-invite link to Align's configured address (https://app.alignsoft.us), not to the host the request was sent to.

Clarified: request size​

  • Align's inbound webhook receivers (for example the GitHub and Stripe webhooks) now accept payloads up to 25 MB. Every other endpoint, including /api/v1, still accepts JSON bodies up to 100 KB.

2026-09-18​

Changed: MCP uses your role in the active organisation​

  • MCP tools now decide what you may do from your role in the organisation you are working in, not from your account's original role. Someone who is a client in one organisation is treated as a client there, even if they are a developer elsewhere.

2026-09-14​

Removed: Slack webhook URL from project responses​

  • Project responses from GET /api/v1/projects and GET /api/v1/projects/{id} no longer include the project's Slack webhook URL (slackWebhookUrl, or its encrypted form slackWebhookUrlEnc). It is a credential.

Changed: time entry pricing​

  • Time entries created with POST /api/v1/projects/{id}/time-entries and POST /api/v1/integration/time-entries are now priced from the person's labour category for that project, the same way as time logged in Align.

2026-09-08​

Added: service levels on projects​

  • POST /api/v1/projects and PATCH /api/v1/projects/{id} accept slaEnabled and slaTargets.

Changed: clearer MCP refusals​

  • When a record exists but is outside your current MCP context (another organisation, or a project your key is not pinned to), MCP tools now say so instead of reporting "not found".

2026-09-07​

Added: per-project workflow states​

  • POST /api/v1/projects/{id}/entries and PATCH /api/v1/entries/{id} accept workflowStatusId, for projects that define their own workflow states.

Added: setting custom fields through MCP​

  • The MCP entry_create and entry_update tools accept customFields.

2026-09-06​

Added: custom fields in MCP​

  • get_entry and the align://entries/{id} resource include an entry's custom fields. list_entries includes the fields the project marks for lists.

2026-09-04​

Fixed: MCP context on the SSE transport​

  • Each SSE connection now keeps its own active organisation and project, as Streamable HTTP connections already did.

2026-09-03​

Added: cost rate on time entries​

  • Time entries created through the API now record costRateSnapshot, the cost rate at the time of logging, alongside hourlyRateSnapshot.

2026-09-02​

Added: SCIM 2.0 provisioning​

  • Identity providers can provision and deprovision users through SCIM 2.0 at https://app.alignsoft.us/scim/v2 (/Users and /ServiceProviderConfig). Authenticate with an API key that holds read:scim_user, write:scim_user and delete:scim_user. SCIM uses the same key checks as the Public API, so the Public API must be turned on for the organisation.

Changed: GET /users lists members by membership​

  • GET /api/v1/users now lists everyone who is a member of your organisation. Before, it relied on an older per-user field, so it could miss members or list someone under an organisation they had left.

Changed: archived organisations​

  • Keys belonging to an archived or deleted organisation are refused with 403 organization_unavailable.
  • semantic_search searched projects the caller could not open. It now searches only projects you can access.

2026-09-01​

Changed: MCP follows project access​

  • MCP tools and resources now show only the projects you can access in Align, instead of every project in the organisation. For an API key, that is the access of the user who created it.
  • MCP cost tools check your role in the active organisation.

Added: separate context per MCP connection​

  • Each Streamable HTTP connection gets its own active organisation and project, identified by the Mcp-Session-Id header. Switching project in one client no longer moves another.

Corrections to earlier entries​

Earlier versions of this changelog described some things that are not in the API. They have been removed from the entries below:

  • POST /api/v1/webhooks/{id}/rotate-secret (2026-04-10) does not exist. To change a subscription's secret, create a new subscription and delete the old one.
  • GET /api/v1/agreements/{id} (2026-05-03) does not exist. Use GET /api/v1/projects/{id}/agreements.
  • GET /api/v1/projects/{id}/audit-events (2026-04-28) does not exist. Use GET /api/v1/audit-events.
  • Project-scoped keys cannot call GET /api/v1/users (2026-04-21); it needs an organisation-scoped key.
  • GET /api/v1/search (2026-04-15) returns up to 50 results; the earlier entry said 25.
  • GET /mcp/privacy (2026-06-04) is not served.
  • GET /api/v1/comments/{id} (2026-03-20) does not exist; comments are read with GET /api/v1/entries/{id}/comments.

2026-06-04​

Added: entry deployment stage tracking​

  • Entry response objects now include a deploymentStage field ("testing" | "staging" | "production" | null). The field is set automatically by the Railway deployment webhook or the GitHub deployment_status webhook when a matching entry is deployed to a tracked environment. It is read-only via the API — deploymentStage is ignored in POST /api/v1/projects/:id/entries and PATCH /api/v1/entries/:id bodies.

Added: MCP server compliance​

  • GET /.well-known/oauth-protected-resource — returns RFC 9728 OAuth Protected Resource metadata. Used by MCP clients (Claude.ai, CODEX) to discover the token endpoint before connecting.
  • All 22 MCP tools now carry OpenAPI-compatible tool annotations (title, readOnlyHint, openWorldHint, destructiveHint). Clients that support tool annotations can use these to surface safe-for-automation indicators in their UI.
  • MCP endpoints now enforce an origin allowlist and return 403 Forbidden for requests from unlisted origins.

2026-05-14​

Added: release evidence signing key management​

  • GET /api/settings/evidence-key — returns whether a signing key is configured and its key prefix (evk_<prefix>). Requires admin role.
  • POST /api/settings/evidence-key — generate (or rotate) the organisation-level HMAC signing key for release evidence packages. Issuing a new key automatically revokes the previous one. The full key (evk_<64hex>) is returned once; store it in your secrets manager immediately.
  • Evidence responses now include X-Align-Evidence-Signature: sha256=<hex> and X-Align-Evidence-Key-Prefix: evk_<prefix> headers when a signing key is configured.

Note: These endpoints are session-authenticated platform-settings routes (/api/settings/) — they are not part of the public v1 API and do not appear in the OpenAPI spec. They are accessible to org admins via the Align web app only.


2026-05-10​

Added: snapshot (report) endpoints​

  • GET /api/v1/projects/:id/snapshots — list report snapshots for a project. Each snapshot includes narrativeSource ('ai' or 'template') and the generated summary text.

The narrativeSource field indicates whether the executive summary was produced by the AI provider or fell back to the template generator (e.g. when the AI provider is unavailable or the prompt was redacted).

Note: Individual snapshot retrieval (GET /api/v1/snapshots/:id) is not yet available in the public API. Use the project list endpoint and filter client-side by id.


2026-05-07​

Added: wiki page endpoints​

  • GET /api/v1/projects/:id/wiki-pages — list wiki pages for a project.
  • POST /api/v1/projects/:id/wiki-pages — create a wiki page. Required fields: title. Optional: content (Markdown).
  • GET /api/v1/wiki-pages/:id — retrieve a single wiki page with full Markdown content.
  • PATCH /api/v1/wiki-pages/:id — update title or content.
  • DELETE /api/v1/wiki-pages/:id — delete a wiki page.

2026-05-03​

Added: agreement endpoints​

  • GET /api/v1/projects/:id/agreements — list agreements for a project.

Creating agreements via the API is not supported in v1.


2026-04-28​

Added: audit event endpoint​

  • GET /api/v1/audit-events — list audit events across the organisation, paginated. Supports entityType, action, and actorId query filters.

Audit events include actorType: 'api_key' and apiKeyId in metadata when the action was performed via an API key.


2026-04-21​

Added: user endpoints​

  • GET /api/v1/users — list users in the organisation, paginated. Returns id, name, email, role, organizationId, and createdAt. Sensitive fields (password hash, MFA secrets) are excluded.
  • GET /api/v1/users/:id — retrieve a single user.

2026-04-15​

Added: global search endpoint​

  • GET /api/v1/search?q=<query> — search across the organisation.

2026-04-10​

Added: outbound webhook subscriptions​

  • GET /api/v1/webhooks — list webhook subscriptions.
  • POST /api/v1/webhooks — create a subscription. hmacSecret is returned once on creation.
  • PATCH /api/v1/webhooks/:id — update destinationUrl, eventNames, enabled, or description.
  • DELETE /api/v1/webhooks/:id — delete a subscription.

2026-04-01​

Added: release evidence endpoint​

  • GET /api/v1/releases/:id/evidence — retrieve a structured evidence package for a release, including the approval chain, quality checklists, entry summary, and GitHub evidence (commits, PRs, CI results).

2026-03-20​

Added: core resource endpoints (initial v1 launch)​

Initial set of endpoints released:

  • GET /api/v1/me — API key identity
  • GET|POST /api/v1/projects — list and create projects
  • GET|PATCH|DELETE /api/v1/projects/:id
  • GET|POST /api/v1/projects/:id/entries — list and create entries
  • GET|PATCH|DELETE /api/v1/entries/:id
  • GET|POST /api/v1/entries/:id/comments
  • PATCH|DELETE /api/v1/comments/:id
  • GET /api/v1/entries/:id/attachments
  • GET|POST /api/v1/projects/:id/releases
  • GET|PATCH|DELETE /api/v1/releases/:id