Outcome
Request approval or activate one organization app connection using its current published declarations and entitlement checks.
POST /api/developer-console/connections/{consumerAppId}/{providerAppId}/enable
Action: app_topolo_developers.connections.enable.
Before you start
Use a legitimate person credential in the original active organization with Developers connections:write. Review and approve the actual request/activation, current declaration and possible subscription provisioning/removal before confirming. A nonadministrator may create or re-request approval in specific states; only the selected organization-admin/platform-access branch performs activation.
No organization id is accepted in action input. This handler derive it from the authenticated user. No workspace resource selector is declared in these exact action inputs or passed by the selected handler; do not invent one or mistake consumer/provider workspaceScope for a credential binding. Shared console authentication/resource/profile initialization is outside these selected handlers; its existing owner-qualified context must remain in force. This source packet does not certify the whole request as zero-write, and no automatic deletion of any profile/mirror is a rollback.
Discover the published consumer/provider pair and read current connection status and declaration before planning. Input is exactly consumerAppId/providerAppId matching ^app_[a-z0-9]+(?:_[a-z0-9]+)+$. No organization/workspace selector, desired status, arbitrary event target, retry token or grant override is admitted.
All examples are complete synthetic source-derived UNRUN carriers with fictional ids and explicit saved-state/dependency premises. No request, activation, Notify subscription, private/provider/grant or business operation was performed; no application import/test. Current descriptor matches immutable7b89, not served-runtime certification.
Request
These ids are fictional. Discover the actual pair and inspect the current plan and declaration impact before confirming a mutation.
{
"consumerAppId": "app_example_consumer",
"providerAppId": "app_example_provider"
}
Requests, approval and partial activation
POST /api/developer-console/connections/{consumerAppId}/{providerAppId}/enable resolves the current published consumer/provider manifests, consumer declaration and provider action/event/reference contracts. Before any selected connection write it rejects missing consumer404 consumer_not_found, no consumed declaration422 connection_not_declared, absent provider409 provider_unavailable or missing provider contracts409 provider_contract_missing (details.missing). It then requires current organization entitlements for both apps: unavailable lookup503 entitlement_unavailable; known missing rights403 not_entitled (details.appIds). Published configuration and entitlement presence are not provider health, paid execution or event delivery proof.
For a nonadministrator with no live row, the service creates/revives a needs_approval request and returnsHTTP202 outcome requested. A new row uses workspaceScope linked if the resolved declaration includes reference types, otherwise all. The request stores the current declaration/digest/source, requester and null approval. This does not activate a connection, provision a subscription or authorize use of a provider.
For a nonadministrator with a live revoked row, it changes only status to needs_approval, clears lastError and updates time, returning202 requested. It does not refresh the stored declaration/requester or erase prior approval history in this branch. With a live needs_approval row it instead returns403 organization_admin_required, even for the requester. Other live statuses return200 unchanged without provisioning; that can include paused/degraded state. Thus repeated request creation is not an idempotent202 operation, and unchanged is not healthy or activated.
For an administrator, a live paused row returns409 connection_paused. Otherwise an existing row gets the current declaration/digest/source saved, then a pending status; a new/revived row is created with the administrator as requester/approver. Initial status is degraded with provisioning in progress when current events/reference events exist, otherwise active. Existing workspaceScope is preserved; enabling does not automatically widen/narrow it.
The approval store refreshes approvedBy/approvedAt only when the old status is needs_approval or revoked, or the saved approval field is null. On other existing statuses it can save a new declaration while retaining older approver/time values. Those retained timestamps do not prove who reviewed the newly saved declaration. Each update is a separate awaited storage operation, not a compare-and-set transaction over entitlement/declaration/provisioning state.
The administrator branch provisions ordinary declared events and Developers reference changed/removed subscriptions sequentially. An existing provisioned nonempty id at the same event version is reused. New or failed subscriptions are provisioned under the connection’s identity; ordinary events use the consumer app, reference events use Developers and a references-suffixed connection identity. Configuration/missing Notify or caught provisioning errors are saved as failed subscription state; a previously known subscription id is retained by the store for later cleanup.
Enabling can also remove saved subscriptions no longer present in the current declaration. Stale ordinary cleanup uses the consumer app; stale reference cleanup uses Developers. A null subscription id permits local deletion without a Notify call; configured removal failures remain saved and contribute to degraded. Do not assume enabling is only additive or that an already configured connection is a no-op.
After provisioning/cleanup, the service sets active if no collected failures, otherwise degraded with the joined failure text. It returnsHTTP200 outcome activated or degraded and the freshly read full ConnectionRecord, including both subscription collections. Degraded is a successful HTTP response carrying incomplete subscription work, not proof of full activation or a generic500. Subscription provisioning is not proof of message delivery or provider operation completion.
The complete envelope is {success:true,message:"OK",data:{outcome:"requested"|"unchanged"|"activated"|"degraded",connection:<full stored row or null>}}. requested usesHTTP202; other outcomes use200. Storage reloads are separate; concurrent changes or a missing final row can affect the returned record. Nonnull TypeScript assertions do not supply a runtime null guard. No organizationId/count/page is added at the outer data level.
An unexpected database/dependency failure may escape after the request, approval, pending state, subscription provisioning/removal or final status has partially changed. No transaction rolls all of those effects back. Read actual current state before any approved retry. Do not invent a new connection id, repeat in parallel, automatically disable or treat an old approval stamp as current execution authority.
No organization override is accepted. The route rejects malformed/conflicting path/body or strict pair input with422 invalid_input and details.body:true. An active organization is required before selected dependencies; absence returns403 organization_required. Native action permission is separate from the source actor.isAdmin branches, and any later provider/workspace use retains its own current grant/access checks.
Worked responses
A nonadministrator requests a new action-only connection
Complete synthetic UNRUN HTTP202. Both manifests/action declarations and entitlements pass; there is no live row. The fictional generated id and time are specified by the fixture. Current declaration has actions only, so the new row uses workspaceScope all.
{
"success": true,
"message": "OK",
"data": {
"outcome": "requested",
"connection": {
"id": "conn_docs_request",
"organizationId": "org_docs_fixture",
"consumerAppId": "app_example_consumer",
"providerAppId": "app_example_provider",
"status": "needs_approval",
"workspaceScope": "all",
"declaration": {
"actions": [
{
"action": "app_example_provider.items.list",
"scopes": [
"items:read"
],
"resource": "workspace",
"optional": false,
"purpose": "Read example items"
}
],
"events": []
},
"declarationDigest": null,
"declarationSource": "topolo.app.json",
"lastError": null,
"requestedBy": "user_docs_requester",
"requestedAt": "2026-10-22T18:00:00.000Z",
"approvedBy": null,
"approvedAt": null,
"removedBy": null,
"removedAt": null,
"createdAt": "2026-10-22T18:00:00.000Z",
"updatedAt": "2026-10-22T18:00:00.000Z",
"subscriptions": [],
"referenceSubscriptions": []
}
}
}
Pending approval is not activated or provisioned; a second nonadmin call on this live pending row returns403 rather than another202.
An administrator rechecks an existing action-only connection
Complete synthetic UNRUN HTTP200. An existing active row has the same shown action declaration and empty subscription collections; current declarations/entitlements pass. Its linked scope and nonnull historical approver/time are retained while updatedAt changes.
{
"success": true,
"message": "OK",
"data": {
"outcome": "activated",
"connection": {
"id": "conn_docs_fixture",
"organizationId": "org_docs_fixture",
"consumerAppId": "app_example_consumer",
"providerAppId": "app_example_provider",
"status": "active",
"workspaceScope": "linked",
"declaration": {
"actions": [
{
"action": "app_example_provider.items.list",
"scopes": [
"items:read"
],
"resource": "workspace",
"optional": false,
"purpose": "Read example items"
}
],
"events": []
},
"declarationDigest": null,
"declarationSource": "topolo.app.json",
"lastError": null,
"requestedBy": "user_docs_requester",
"requestedAt": "2026-10-21T08:00:00.000Z",
"approvedBy": "user_docs_approver",
"approvedAt": "2026-10-21T08:00:00.000Z",
"removedBy": null,
"removedAt": null,
"createdAt": "2026-10-21T08:00:00.000Z",
"updatedAt": "2026-10-22T18:00:00.000Z",
"subscriptions": [],
"referenceSubscriptions": []
}
}
}
Outcome activated does not require new approval stamps or prove provider execution/delivery. The helper does not change existing workspaceScope.
Stale reference-subscription cleanup leaves a degraded result
Complete synthetic UNRUN HTTP200. Current declaration is action-only, but the prior row has the two historical subscription collections shown in the accepted connection-list fixture. Its null-id ordinary subscription is locally deleted; stale reference subscription has a saved id but no configured Notify dependency, so cleanup is recorded failed.
{
"success": true,
"message": "OK",
"data": {
"outcome": "degraded",
"connection": {
"id": "conn_docs_fixture",
"organizationId": "org_docs_fixture",
"consumerAppId": "app_example_consumer",
"providerAppId": "app_example_provider",
"status": "degraded",
"workspaceScope": "linked",
"declaration": {
"actions": [
{
"action": "app_example_provider.items.list",
"scopes": [
"items:read"
],
"resource": "workspace",
"optional": false,
"purpose": "Read example items"
}
],
"events": []
},
"declarationDigest": null,
"declarationSource": "topolo.app.json",
"lastError": "app_example_provider example.reference.changed@1 (references): Notify is not configured for this environment",
"requestedBy": "user_docs_requester",
"requestedAt": "2026-10-21T08:00:00.000Z",
"approvedBy": "user_docs_approver",
"approvedAt": "2026-10-21T08:00:00.000Z",
"removedBy": null,
"removedAt": null,
"createdAt": "2026-10-21T08:00:00.000Z",
"updatedAt": "2026-10-22T18:00:00.000Z",
"subscriptions": [],
"referenceSubscriptions": [
{
"sourceAppId": "app_example_provider",
"eventType": "example.reference.changed",
"eventVersion": 1,
"purpose": "changed",
"referenceTypes": [
"example.item"
],
"subscriptionId": "whs_docs_fixture",
"status": "failed",
"lastError": "Notify is not configured for this environment",
"updatedAt": "2026-10-22T18:00:00.000Z"
}
]
}
}
}
Degraded is a200 partial-work carrier, and the old reference subscription id remains discoverable. Do not report full activation or blind-retry the mutation.
An ordinary member observes an unchanged degraded row
Complete synthetic UNRUN HTTP200. Current declaration/entitlement checks pass; an ordinary nonadmin has a live degraded row. The service returns that original full row without provisioning or updates.
{
"success": true,
"message": "OK",
"data": {
"outcome": "unchanged",
"connection": {
"id": "conn_docs_fixture",
"organizationId": "org_docs_fixture",
"consumerAppId": "app_example_consumer",
"providerAppId": "app_example_provider",
"status": "degraded",
"workspaceScope": "linked",
"declaration": {
"actions": [
{
"action": "app_example_provider.items.list",
"scopes": [
"items:read"
],
"resource": "workspace",
"optional": false,
"purpose": "Read example items"
}
],
"events": []
},
"declarationDigest": null,
"declarationSource": "topolo.app.json",
"lastError": "Synthetic subscription provisioning failure",
"requestedBy": "user_docs_requester",
"requestedAt": "2026-10-21T08:00:00.000Z",
"approvedBy": "user_docs_approver",
"approvedAt": "2026-10-21T08:00:00.000Z",
"removedBy": null,
"removedAt": null,
"createdAt": "2026-10-21T08:00:00.000Z",
"updatedAt": "2026-10-21T08:00:00.000Z",
"subscriptions": [
{
"sourceAppId": "app_example_provider",
"eventType": "example.updated",
"eventVersion": 1,
"subscriptionId": null,
"status": "failed",
"lastError": "Synthetic provisioning failure",
"updatedAt": "2026-10-21T08:00:00.000Z"
}
],
"referenceSubscriptions": [
{
"sourceAppId": "app_example_provider",
"eventType": "example.reference.changed",
"eventVersion": 1,
"purpose": "changed",
"referenceTypes": [
"example.item"
],
"subscriptionId": "whs_docs_fixture",
"status": "provisioned",
"lastError": null,
"updatedAt": "2026-10-21T08:00:00.000Z"
}
]
}
}
}
Unchanged does not mean healthy, entitled forever or repaired; no automatic provider action follows.
A pending request requires an administrator to approve
Complete synthetic UNRUN HTTP403 for a nonadmin after current declaration/entitlement checks with a live needs_approval row.
{
"success": false,
"error": {
"message": "Only an organization admin can approve a pending connection request",
"code": "organization_admin_required"
}
}
Preserve the actual request and obtain legitimate approval; do not swap credentials or create another identity.
An administrator cannot enable a paused row
Complete synthetic UNRUN HTTP409 for the administrator branch with a live paused row after prerequisite checks.
{
"success": false,
"error": {
"message": "Resume the paused connection instead of enabling it",
"code": "connection_paused"
}
}
Inspect the existing supported state-management workflow; do not invent a resume action or force a new connection.
Organization entitlement lookup is unavailable
Complete synthetic UNRUN HTTP503 when declaration checks pass but the entitlement dependency returns null before any selected connection write. Shared context initialization is outside this no-connection-write statement.
{
"success": false,
"error": {
"message": "Topolo Auth could not confirm the organization entitlements",
"code": "entitlement_unavailable"
}
}
Preserve the original scope and actual error. Resolve the dependency through its owner; do not treat a stored active status as a replacement for current entitlement verification.
Verify and recover
-
Read connections.status and the stored live pair in the original organization after any response. Compare the actual outcome, status, nullable entitlements, current versus approved declaration, approval history, workspaceScope and both subscription collections to the reviewed intent.
-
Treat202 requested as pending approval and200 degraded as incomplete subscription work. Do not execute provider actions, send business events or widen workspace/person grants from either. Even activated does not prove delivery or provider health.
-
After an uncertain or failed call, preserve request ids/errors and current record. A later same-pair enable can perform further writes, replace the declaration and remove stale subscriptions; it requires renewed review of actual remaining work and current source policy, not an automatic retry token.
-
Do not erase historical records, create a fresh pair/id, disable or publish declarations as automatic recovery. Resolve the concrete manifest/entitlement/Notify issue through its owner. Paused is not a command to enable or broaden authority; inspect the existing supported pause/resume workflow rather than guessing an endpoint.
No automatic inverse. First reconcile current request/approval/subscription/declaration outcomes. A separately approved administrator disable performs its own cleanup and placement effects, cannot recall delivered/queued events, and is not an exact rollback. Never create duplicate identities or blindly repeat enable to conceal unknown effects.
Related actions
- Inspect connection status before and after the reviewed action.
- Disable an organization connection only as a separately approved operation.
Change log
- 2026-10-22: Added exact request/admin state branches, current declaration/entitlement checks, approval-stamp limits, provisioning and stale-subscription cleanup, full200/202/refusal examples and partial-outcome recovery. All examples synthetic UNRUN; no live activation or delivery certified.