Topolo Docs Topolo Platform
Open workspace

Approve a workspace link

Record eligible workspace-admin approvals and distinguish approved, activated and unchanged outcomes.

Approve a workspace link

Record eligible workspace-admin approvals and distinguish approved, activated and unchanged outcomes.

Action and scope

app_topolo_developers.workspace_links.approve

POST /api/developer-console/workspace-links/{linkId}/approve

Mutation; explicit confirmation is required.

Before you start

Use the intended environment, authenticated identity and active organization. Discover actual link/pair identities; every worked value is fictional and every example is SYNTHETIC / UNRUN.

Use the current credential-scoped contract and any required transport resource binding separately from action input. No input field overrides the active organization.

Source and declared-action revision are 7b89bd3b39092cdc29f87540847bf99a243f0a40. The separate Docs payload-format schema revision9530cc90f2762ce1c59d63175ff37fb23a1b24ba is not the Developers source revision.

Declared permission: app_topolo_developers.connections:write. Read the actual link/pair and relevant access first.

This action can change workspace connectivity or placement access. Review the actual current state and affected pair, obtain explicit approval for those effects, then provide the published CLI/MCP confirmation only for that intended mutation. No worked example executes or authorizes it.

A link row, organization role or successful response is not a new provider permission grant. Caller and membership/approval boundaries below still apply.

Input fields

FieldRequiredType and constraints
linkIdYesstring; pattern ^wsl_[A-Za-z0-9-]{1,80}$

The action input is closed. Path linkId and any supplied representation must agree; no organization override, idempotency key or expected version is accepted.

Behavior and response

Success uses {success:true,message:"OK",data:...}. A list has organizationId,links,count. A mutation has outcome and the complete link record; unlink also has accessRemoved. The declared data schema is open, and the complete source-qualified examples below retain every link-record field.

Finds a live link by id in the active organization. Already active returns HTTP200 unchanged before per-workspace membership/admin lookup; that result does not certify the caller’s workspace-admin access or add an approval.

For a pending row, Auth membership lookup for each app must be available. Only the sides on which the caller has workspace accessLevel admin and which have no approval yet are written. Missing membership on one side can coexist with valid admin access on the other.

The caller’s own new approval(s) are recorded first, then a separate update changes status to active only when both approval fields are nonnull. Result is activated when active, approved when still pending, or unchanged when an administered side already approved. Neither admin side is403 with the awaiting pair strings.

This selected approval helper does not recheck current app-connection status, current reference declarations or provider authorization. Organization-admin status alone is not used as a pending-side approval override.

There is no supplied idempotency key, expected-current predicate or transaction wrapping the two updates in this selected helper. An error/unknown response can follow a partial approval write. Read the same pair/id, approvals and status before any further authorized action.

Errors and recovery

HTTP 403 · organization_required — Select the intended active organization through supported context controls.

HTTP 422 · invalid_input — Use only the exact declared fields and canonical id syntax; preserve current path/body agreement.

HTTP 404 · link_not_found — Read the retained exact pair under the original organization; do not guess a replacement id.

HTTP 503 · workspace_access_unavailable — Recover Auth lookup availability before a pending-side decision.

HTTP 403 · workspace_admin_required — Only an actual pending workspace-admin side can add its approval; an organization role alone is not used as this override.

Shared authentication, declared permission or framework failures may occur before these selected branches. Uncaught storage/concurrency failures can have a different carrier; preserve actual status/body and do not infer no effects from a failed response.

Worked examples — synthetic and unrun

SOURCE-DERIVED SYNTHETIC UNRUN HTTP 200. Assume a live pending row with its consumer approval already retained. Caller administers the provider workspace; Auth resolves both membership sets and store updates succeed at the later timestamp. Outer authentication/permission and explicit confirmation are satisfied in this UNRUN fixture.

Input:

{
  "linkId": "wsl_00000000-0000-4000-8000-000000000001"
}

Complete response body:

{
  "success": true,
  "message": "OK",
  "data": {
    "outcome": "activated",
    "link": {
      "id": "wsl_00000000-0000-4000-8000-000000000001",
      "organizationId": "org_docs_fixture",
      "consumerAppId": "app_docs_consumer",
      "consumerWorkspaceId": "ws_consumer_fixture",
      "providerAppId": "app_docs_provider",
      "providerWorkspaceId": "ws_provider_fixture",
      "status": "active",
      "requestedBy": "user_fixture_requester",
      "requestedAt": "2026-10-23T00:00:00.000Z",
      "consumerApprovedBy": "user_fixture_consumer_admin",
      "consumerApprovedAt": "2026-10-23T00:00:00.000Z",
      "providerApprovedBy": "user_fixture_provider_admin",
      "providerApprovedAt": "2026-10-23T00:01:00.000Z",
      "removedBy": null,
      "removedAt": null,
      "createdAt": "2026-10-23T00:00:00.000Z",
      "updatedAt": "2026-10-23T00:01:00.000Z"
    }
  }
}

Both approval fields and active status are present. This selected approve action does not recheck current app-connection status; an active link alone does not establish provider access or a usable connection.

Approving one side leaves the other side pending

SOURCE-DERIVED SYNTHETIC UNRUN HTTP 200. Assume a live pending row with no approvals. Caller administers the consumer workspace and has no provider workspace membership; the provider membership lookup succeeds with an empty result. Only the consumer side is approved at the later timestamp.

Input:

{
  "linkId": "wsl_00000000-0000-4000-8000-000000000001"
}

Complete response body:

{
  "success": true,
  "message": "OK",
  "data": {
    "outcome": "approved",
    "link": {
      "id": "wsl_00000000-0000-4000-8000-000000000001",
      "organizationId": "org_docs_fixture",
      "consumerAppId": "app_docs_consumer",
      "consumerWorkspaceId": "ws_consumer_fixture",
      "providerAppId": "app_docs_provider",
      "providerWorkspaceId": "ws_provider_fixture",
      "status": "needs_approval",
      "requestedBy": "user_fixture_requester",
      "requestedAt": "2026-10-23T00:00:00.000Z",
      "consumerApprovedBy": "user_fixture_consumer_admin",
      "consumerApprovedAt": "2026-10-23T00:01:00.000Z",
      "providerApprovedBy": null,
      "providerApprovedAt": null,
      "removedBy": null,
      "removedAt": null,
      "createdAt": "2026-10-23T00:00:00.000Z",
      "updatedAt": "2026-10-23T00:01:00.000Z"
    }
  }
}

Outcome approved is not activation. Provider approval remains null, and current app-connection usability has not been checked by this selected approval branch.

Already active returns unchanged before membership lookup

SOURCE-DERIVED SYNTHETIC UNRUN HTTP 200. Assume outer authentication, intended active organization, connections:write and explicit authorization for the request. The same-organization live row is already active. This branch returns before adminSides and does not call its membership helper.

Input:

{
  "linkId": "wsl_00000000-0000-4000-8000-000000000001"
}

Complete response body:

{
  "success": true,
  "message": "OK",
  "data": {
    "outcome": "unchanged",
    "link": {
      "id": "wsl_00000000-0000-4000-8000-000000000001",
      "organizationId": "org_docs_fixture",
      "consumerAppId": "app_docs_consumer",
      "consumerWorkspaceId": "ws_consumer_fixture",
      "providerAppId": "app_docs_provider",
      "providerWorkspaceId": "ws_provider_fixture",
      "status": "active",
      "requestedBy": "user_fixture_requester",
      "requestedAt": "2026-10-23T00:00:00.000Z",
      "consumerApprovedBy": "user_fixture_consumer_admin",
      "consumerApprovedAt": "2026-10-23T00:00:00.000Z",
      "providerApprovedBy": "user_fixture_provider_admin",
      "providerApprovedAt": "2026-10-23T00:00:00.000Z",
      "removedBy": null,
      "removedAt": null,
      "createdAt": "2026-10-23T00:00:00.000Z",
      "updatedAt": "2026-10-23T00:00:00.000Z"
    }
  }
}

Stored active state is returned; this does not certify workspace-admin authority, membership, a new approval or current connection usability. Confirmation remains required because state can differ at execution time.

An already approved side has nothing new to add

SOURCE-DERIVED SYNTHETIC UNRUN HTTP 200. Assume the consumer side of a pending row already approved, caller is consumer workspace admin, and the provider membership lookup succeeds but grants no admin side. The other side remains unapproved.

Input:

{
  "linkId": "wsl_00000000-0000-4000-8000-000000000001"
}

Complete response body:

{
  "success": true,
  "message": "OK",
  "data": {
    "outcome": "unchanged",
    "link": {
      "id": "wsl_00000000-0000-4000-8000-000000000001",
      "organizationId": "org_docs_fixture",
      "consumerAppId": "app_docs_consumer",
      "consumerWorkspaceId": "ws_consumer_fixture",
      "providerAppId": "app_docs_provider",
      "providerWorkspaceId": "ws_provider_fixture",
      "status": "needs_approval",
      "requestedBy": "user_fixture_requester",
      "requestedAt": "2026-10-23T00:00:00.000Z",
      "consumerApprovedBy": "user_fixture_consumer_admin",
      "consumerApprovedAt": "2026-10-23T00:00:00.000Z",
      "providerApprovedBy": null,
      "providerApprovedAt": null,
      "removedBy": null,
      "removedAt": null,
      "createdAt": "2026-10-23T00:00:00.000Z",
      "updatedAt": "2026-10-23T00:00:00.000Z"
    }
  }
}

The pending row and timestamps are retained. Another side’s approval is still required; do not loop on unchanged as a recovery strategy.

Neither workspace is administered by this caller

SOURCE-DERIVED SYNTHETIC UNRUN HTTP 403. Assume both membership lookups succeed but neither side gives workspace-admin access, and the pending row has no approvals. No approval write occurs.

Input:

{
  "linkId": "wsl_00000000-0000-4000-8000-000000000001"
}

Complete response body:

{
  "success": false,
  "error": {
    "message": "Only an admin of a linked workspace can approve this link",
    "code": "workspace_admin_required",
    "details": {
      "awaiting": [
        "app_docs_consumer/ws_consumer_fixture",
        "app_docs_provider/ws_provider_fixture"
      ]
    }
  }
}

Organization-admin status by itself is not used as an approval bypass in this selected pending-link branch.

Verify the result

Retain the original organization, exact pair/link id, pre-write record, approved effects and actual request/response identity. Read workspace_links.list with the exact four pair filters and compare id,status,approvals and timestamps.

A successful outcome can be linked,requested,approved,activated or unchanged depending on the action and current state. Confirm the intended final state; do not equate HTTP200 with new approval, active usability or attribution to this particular request.

After an unknown outcome, reconcile current link state before any further request. For unlink, also read the relevant placements under separate authorized read scope; a removed link alone does not prove a successful cascade.

Recovery boundary

First read current approvals and status after an unknown result. The selected API has no one-side approval withdrawal action. workspace_links.unlink removes the whole live link and can affect placements; treat it as a separate approved compensation rather than an exact reversal of one approval.

  • app_topolo_developers.workspace_links.list
  • app_topolo_developers.workspace_links.unlink
  • app_topolo_developers.references.search

Source provenance and limits

Reviewed immutable Developers 7b89bd3b39092cdc29f87540847bf99a243f0a40 (tree b3817ca104370c067b373f1f9899b57f8283d086), selected placement route/service/store, caller context, connection lookup, actor policy and HTTP envelope. The saved Developers descriptors also declare 7b89bd3b39092cdc29f87540847bf99a243f0a40. Docs native-format validation separately uses9530cc90f2762ce1c59d63175ff37fb23a1b24ba. Source/declaration agreement does not certify serving adoption, transactionality, a runtime business result or current provider authorization. All examples are source-derived synthetic and unrun; automatic Knowledge invocation during builds remains UNKNOWN.

Change log

  • 2026-10-23: Initial documentation of workspace_links.approve with exact state/access boundaries, complete synthetic unrun responses, verification and recovery limits. No application behavior change is asserted.