Outcome
Inspect one application connection’s stored state, current declaration and organization-entitlement diagnostics together.
GET /api/developer-console/connections/{consumerAppId}/{providerAppId}
Action: app_topolo_developers.connections.status.
Before you start
These guides document customer-facing organization reads: documentation may be public, while returned organization records remain private to the authenticated authorized context. Native metadata declares static permission app_topolo_developers.connections:read, allowedServices:[] and no principalAccess override. A person credential with the required permission and active organization is the worked-request principal; no service grant or API-key/resource bypass is created or inferred. Follow the current credential-scoped catalog/target policy for any other principal.
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 consumerAppId and providerAppId from the published application/declaration catalog and original organization connection list. Input is exactly these two app ids; both must match ^app_[a-z0-9]+(?:_[a-z0-9]+)+$. Do not pass organizationId, workspaceId, status, pagination or a provider URL. This read does not require organization-admin status in the selected service; enable and scope changes have separate authorization.
All examples are complete synthetic source-derived UNRUN carriers with fictional ids and explicitly stated catalog/entitlement/store premises. No private connection read, provider/action execution, enable/disable, grant, notification or business operation was performed. Exact immutable source equals the current declaration revision; serving runtime is not certified.
Request
Discover both real application ids before using the supported current contract. These identifiers are fictional:
{
"consumerAppId": "app_example_consumer",
"providerAppId": "app_example_provider"
}
Interpret the status
GET /api/developer-console/connections/{consumerAppId}/{providerAppId} returns the ordinary JSON envelope {success:true,message:"OK",data:{consumerAppId,providerAppId,state,reasons,connection,declaration,entitlements,missingProviderContracts}}. This is a composed organization status view, not a public connection listing or an execution result. There is no outer organizationId/count/page/timestamp field in this status carrier.
The service resolves the consumer and provider published manifests sequentially, loads the consumer stored declaration, checks each declared provider action and published event version, and, for declared reference types, reads the provider declaration and its reference change/remove event contracts. It then reads the exact organization/consumer/provider connection and current organization entitlements. These are separate reads without a single snapshot or cross-store transaction.
Declaration problems are consumer_not_published, connection_not_declared, provider_not_published and provider_contract_missing. Missing action/event/reference contracts are returned in missingProviderContracts. They are diagnostic strings, not a stable parsed grant schema. Ordinary absence produces a successful status view; this status path does not call requireEnableable or turn these problems into enable-style404/409/422 errors. Dependency exceptions can still propagate; absence and read failure are not interchangeable.
connection is the complete stored ConnectionRecord, including both subscriptions and referenceSubscriptions, or null. A record with a truthy removedAt is treated as no live record; an unremoved record whose status is disabled still counts as live and reports that stored status. The returned record includes organizationId, identity/workspaceScope/declaration source/digest, request/approval/removal actors and timestamps, lastError and subscription status/error details. These remain private to the legitimate organization reader and are saved history, not current delivery/approval/access proof.
With a live record, state starts from its stored status. If current entitlements are known and either app is not entitled, only active/degraded/paused becomes revoked in this view. The stored record is not rewritten, so state can be revoked while connection.status remains degraded. Other live statuses are retained. A truthy stored lastError adds last_error to reasons but does not itself change state.
If the entitlement dependency returns null, entitlements is null and reasons includes entitlement_unavailable. A live active row can still show state active in that same response; do not treat that state as an entitlement check passing. If entitlements are known, they are exactly {consumer:boolean,provider:boolean}; either false adds not_entitled.
Without a live record, state is needs_setup only when the combined reasons array is empty, otherwise not_connected. needs_setup means the current declaration and entitlement diagnostics passed this computation. The function does not inspect actor.isAdmin before choosing needs_setup, so this state neither grants enable authority nor guarantees a later enable request will succeed.
declaration contains source, nullable digest, current actions/events, optional references only when nonempty, and changedSinceApproval. Action snapshots include action/scopes/resource/optional/purpose; events include source/type/version/deliver/scope/optional/purpose; references include source/type/placedIn/optional/purpose. optional defaults true unless explicitly false. Undefined optional properties are omitted from serialized JSON. These declarations are configuration, not approval, scopes currently granted to the caller or permission to execute any declared action.
changedSinceApproval compares JSON.stringify(live.declaration) to JSON.stringify(the current snapshot) when live exists; otherwise false. It is a serialization comparison, not a canonical semantic digest, runtime conformance check, policy approval or repair. source/digest describe declaration provenance; missing stored declaration uses source topolo.app.json and digest null.
This selected status service does not write connection state, provision subscriptions, emit Notify events, mint/revoke grants, change workspace scope or call the declared provider business actions. It does consult catalog/entitlement dependencies and shared console authentication/context may initialize local profile/mirror state outside this selected path. A status refusal is not evidence that the complete request had no effects, and no automatic deletion is justified.
Worked responses
A declared and entitled pair with no saved live connection
Complete synthetic UNRUN HTTP200. Both manifests and the named action are published, the consumer declaration matches the shown snapshot, both apps are entitled and no live connection row exists.
{
"success": true,
"message": "OK",
"data": {
"consumerAppId": "app_example_consumer",
"providerAppId": "app_example_provider",
"state": "needs_setup",
"reasons": [],
"connection": null,
"declaration": {
"source": "topolo.app.json",
"digest": null,
"actions": [
{
"action": "app_example_provider.items.list",
"scopes": [
"items:read"
],
"resource": "workspace",
"optional": false,
"purpose": "Read example items"
}
],
"events": [],
"changedSinceApproval": false
},
"entitlements": {
"consumer": true,
"provider": true
},
"missingProviderContracts": []
}
}
No automatic enable follows. An ordinary authorized reader can see needs_setup without being an organization admin.
Known entitlement withdrawal changes the view without rewriting history
Complete synthetic UNRUN HTTP200. Published declaration/action still match; the full stored degraded connection has a lastError and both subscription collections. The entitlement check now excludes the provider.
{
"success": true,
"message": "OK",
"data": {
"consumerAppId": "app_example_consumer",
"providerAppId": "app_example_provider",
"state": "revoked",
"reasons": [
"not_entitled",
"last_error"
],
"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"
}
]
},
"declaration": {
"source": "topolo.app.json",
"digest": null,
"actions": [
{
"action": "app_example_provider.items.list",
"scopes": [
"items:read"
],
"resource": "workspace",
"optional": false,
"purpose": "Read example items"
}
],
"events": [],
"changedSinceApproval": false
},
"entitlements": {
"consumer": true,
"provider": false
},
"missingProviderContracts": []
}
}
state revoked and connection.status degraded intentionally differ. This read did not persist revocation or prove event delivery.
Active stored state with entitlement verification unavailable
Complete synthetic UNRUN HTTP200. A stored active unremoved connection exists and declaration checks pass, but the entitlement dependency returns null. Its saved subscription lists happen to be empty.
{
"success": true,
"message": "OK",
"data": {
"consumerAppId": "app_example_consumer",
"providerAppId": "app_example_provider",
"state": "active",
"reasons": [
"entitlement_unavailable"
],
"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-21T08:00:00.000Z",
"subscriptions": [],
"referenceSubscriptions": []
},
"declaration": {
"source": "topolo.app.json",
"digest": null,
"actions": [
{
"action": "app_example_provider.items.list",
"scopes": [
"items:read"
],
"resource": "workspace",
"optional": false,
"purpose": "Read example items"
}
],
"events": [],
"changedSinceApproval": false
},
"entitlements": null,
"missingProviderContracts": []
}
}
Active is retained as stored state, not a successful entitlement/access check. Preserve unknown authority; do not execute declared actions from this result.
Neither app is published and no declaration or connection exists
Complete synthetic UNRUN HTTP200. Both manifests, stored consumer declaration and live connection are absent; entitlement dependency returns null. Empty missingProviderContracts does not cancel the explicit missing-manifest problems.
{
"success": true,
"message": "OK",
"data": {
"consumerAppId": "app_example_consumer",
"providerAppId": "app_example_provider",
"state": "not_connected",
"reasons": [
"consumer_not_published",
"connection_not_declared",
"provider_not_published",
"entitlement_unavailable"
],
"connection": null,
"declaration": {
"source": "topolo.app.json",
"digest": null,
"actions": [],
"events": [],
"changedSinceApproval": false
},
"entitlements": null,
"missingProviderContracts": []
}
}
Absence is represented as diagnostic success. Do not replace it with a fabricated404 or enable request.
No active organization is available
Complete synthetic UNRUN HTTP403 before selected connection dependencies run. This is the literal error code for this branch, unlike diagnostic reasons in a200 body.
{
"success": false,
"error": {
"message": "An active organization is required to manage app connections",
"code": "organization_required"
}
}
Authenticate/select the intended authorized organization through the supported identity workflow. Do not add organizationId to this action input or switch context automatically.
Verify and recover
-
Compare actual data.consumerAppId/providerAppId and any connection.organizationId with the separately discovered pair and original authenticated organization. Keep the context fixed; no input organization override exists.
-
Read state together with reasons, nullable entitlements, connection.status and missingProviderContracts. Treat entitlement_unavailable as unknown even when state says active, and needs_setup as diagnostics rather than permission.
-
Compare the current declaration and approved stored snapshot before proposing a separate enable/scope mutation. Do not clear errors, rotate grants, enable or disable automatically to make the view green. Any change needs its own supported current contract and authority.
-
Preserve actual errors and request ids on dependency failure; do not convert an exception into missing/not_connected. A later supported read may be appropriate after the owner resolves the issue, but avoid parallel or unchanged retry loops.
Selected service is a composed status read; it has no automatic inverse. Preserve original context and any shared initialization. Do not enable/disable, revoke/regrant, mutate scopes or delete records as recovery; reconcile actual diagnostics and owner failures first.
Related actions
- List organization connections to discover stored pairs within the original organization.
- Browse declared connection capabilities to inspect declaration-derived suggestions separately from grants.
Change log
- 2026-10-22: Added the complete composed status carrier, derived-versus-stored state rules, unknown entitlements, declaration-difference limits and five full synthetic UNRUN cases. No runtime or provider execution is certified.