Action and scope
app_topolo_developers.workspaces.data.export
GET /api/developer-console/workspaces/{workspaceId}/data
Export selected Developers-owned workspace records and projections with field-name redaction and explicit coverage limits.
Before you start
Use the intended environment, authenticated identity and organization. Discover the canonical app-scoped Developers workspace through supported Auth workspace discovery, then use the same actual workspaceId in the action input and resource binding. A path/header is a request, not an access grant. Platform membership resolution is required; an organization role alone is not proof of a sufficient workspace grant.
Required application permission: app_topolo_developers.workspace:read. Platform workspace minimum access requested by the route: read. Service permission and the actual workspace authorization are separate checks.
Input
workspaceId— required, nonempty string. It must match the actual platform-approved workspace resource.- Additional input properties are not accepted. Do not add a JSON confirmation flag.
What it does
The response has schemaVersion, exportedAt, workspaceId, organizationId, retention and data inside the standard {success,message,data} wrapper. data.control includes profiles, apps, submissions, commerce, payoutAccounts, payoutEvents, syncFailures, assuranceSubmissions and assuranceDecisions; data.integrations includes apiKeyResources, p2pCapabilities and actionDefinitions; data.artifacts includes mobileArtifacts and iconObjects; data.catalog includes overlays, registry, directory, collections and partitions; data.intake includes buildRequests. Action definitions are an array of per-app row arrays, not one flattened array. Catalog partitions omit null results.
Queries use the resolved workspace. App-dependent catalog/action/icon projections use app IDs found in that workspace; legacy build requests with workspace_id NULL are also selected for its profile IDs. Data across the stores is collected concurrently without a cross-store snapshot guarantee. A concurrent mutation can change different collections between reads.
Redaction recursively replaces values whose FIELD NAME matches /(password|secret|token|credential|private[-]?key|transfer[-]?code|code[_-]?hash)/i with [REDACTED]. It parses valid object/array JSON strings and recursively processes them, so a database string can become structured JSON. Invalid JSON remains unchanged. Arbitrary sensitive values under non-matching field names can remain; matching non-secret identifiers/schema keys can be over-redacted. This is not complete sanitization.
The export includes R2 icon object metadata, not file bytes; the optional bucket being absent produces no icon objects. Listing uses app-icons/{appId}/ prefixes and cursor pages. Mobile artifact records are not artifact file contents. Auth-owned credentials and the canonical Auth workspace record are outside the selected app-owned export. Actual exported customer data remains private and needs appropriate handling.
The catalog marks this action read-only. Its shared resolver can nevertheless ensure a local workspace mirror and, for an enabled organization without a developer profile, initialize that profile. GET permits suspended reads but still refuses revoked access; it is not a bypass of platform workspace authorization. A foreign platform-admin seeded-profile path is separately scoped by the source; it is not a generic organization-role exception.
Worked examples — synthetic and unrun
Every identifier, value, store result and response below is fictional. The full bodies are conditional illustrations of the pinned source branches; no live action or test was run.
Profile metadata is redacted in a complete illustrative export
SYNTHETIC / UNRUN. Conditional source illustration: the profile query returns exactly the shown fictional row, with metadata initially the JSON string {"apiToken":"fictional-value","description":"Fictional private note; ordinary values are not automatically removed."}; all other queries return no records, there are no apps and no icon objects. Rows are open raw database records; this is a complete conditional response, not an exhaustive production column schema. The nested metadata JSON string becomes an object after recursive redaction.
Request input:
{
"workspaceId": "ws_synthetic_developers"
}
Illustrative HTTP 200 response under the stated fictional preconditions. No action was executed.
{
"success": true,
"message": "Developer workspace data exported successfully.",
"data": {
"schemaVersion": 1,
"exportedAt": "2026-10-23T00:00:00.000Z",
"workspaceId": "ws_synthetic_developers",
"organizationId": "org_synthetic_developers",
"retention": {
"workspaceData": "Retained for the active workspace lifetime or until confirmed erasure.",
"publishedCatalogProjections": "Retained while the owning app is published; removed by confirmed workspace erasure.",
"authCredentials": "Owned by Topolo Auth and excluded from this app-owned export."
},
"data": {
"control": {
"profiles": [
{
"id": "dev_synthetic_profile",
"organization_id": "org_synthetic_developers",
"workspace_id": "ws_synthetic_developers",
"user_id": "usr_synthetic_owner",
"email": "owner@example.invalid",
"name": "Synthetic Owner",
"company_name": "Synthetic Studio",
"website_url": "https://studio.example.invalid",
"plan_preference": "monthly",
"status": "active",
"workspace_access_status": "active",
"onboarding_state": "complete",
"review_state": "approved",
"onboarding_step": 2,
"source": "developer-console",
"metadata": {
"apiToken": "[REDACTED]",
"description": "Fictional private note; ordinary values are not automatically removed."
},
"created_at": 1792713600,
"updated_at": 1792713600
}
],
"apps": [],
"submissions": [],
"commerce": [],
"payoutAccounts": [],
"payoutEvents": [],
"syncFailures": [],
"assuranceSubmissions": [],
"assuranceDecisions": []
},
"integrations": {
"apiKeyResources": [],
"p2pCapabilities": [],
"actionDefinitions": []
},
"artifacts": {
"mobileArtifacts": [],
"iconObjects": []
},
"catalog": {
"overlays": [],
"registry": [],
"directory": [],
"collections": [],
"partitions": []
},
"intake": {
"buildRequests": []
}
}
}
}
No selected records in the export collections
SYNTHETIC / UNRUN. A valid authorized context has resolved this workspace and all selected data queries return empty arrays. This is a conditional collection example, not evidence of erasure and not a universal post-erasure response.
Request input:
{
"workspaceId": "ws_synthetic_developers"
}
Illustrative HTTP 200 response under the stated fictional preconditions. No action was executed.
{
"success": true,
"message": "Developer workspace data exported successfully.",
"data": {
"schemaVersion": 1,
"exportedAt": "2026-10-23T00:00:00.000Z",
"workspaceId": "ws_synthetic_developers",
"organizationId": "org_synthetic_developers",
"retention": {
"workspaceData": "Retained for the active workspace lifetime or until confirmed erasure.",
"publishedCatalogProjections": "Retained while the owning app is published; removed by confirmed workspace erasure.",
"authCredentials": "Owned by Topolo Auth and excluded from this app-owned export."
},
"data": {
"control": {
"profiles": [],
"apps": [],
"submissions": [],
"commerce": [],
"payoutAccounts": [],
"payoutEvents": [],
"syncFailures": [],
"assuranceSubmissions": [],
"assuranceDecisions": []
},
"integrations": {
"apiKeyResources": [],
"p2pCapabilities": [],
"actionDefinitions": []
},
"artifacts": {
"mobileArtifacts": [],
"iconObjects": []
},
"catalog": {
"overlays": [],
"registry": [],
"directory": [],
"collections": [],
"partitions": []
},
"intake": {
"buildRequests": []
}
}
}
}
URL and authorized workspace disagree
SYNTHETIC / UNRUN. The request is authorized for a different workspace from the path/input workspaceId; the explicit source guard refuses. Shared context resolution ran first and may already have ensured its authorized local mirror/profile.
Request input:
{
"workspaceId": "ws_synthetic_developers"
}
Illustrative HTTP 403 response under the stated fictional preconditions. No action was executed.
{
"success": false,
"error": {
"message": "You do not have access to this workspace."
}
}
A store read fails
SYNTHETIC / UNRUN. Conditional fixture: a queried store throws Error("Synthetic export store failure."); the outer source handler returns error.message. No partial export is returned. Earlier context initialization may have persisted; the fictional text is not a stable provider error code.
Request input:
{
"workspaceId": "ws_synthetic_developers"
}
Illustrative HTTP 500 response under the stated fictional preconditions. No action was executed.
{
"success": false,
"error": {
"message": "Synthetic export store failure."
}
}
Errors and recovery
This is an explanatory label, not a wire error.code. The source message is You do not have access to this workspace. Reconcile URL/input and actual platform-approved resource context; do not substitute an unauthorized target.
This is an explanatory label, not a stable wire code. The outer handler returns an Error message; preserve the request and UNKNOWN/partial effects. A read collection has no compensating data action. On failure, preserve the response and selected context; reconcile any shared resolver initialization separately. Correct authorization/scope before a new authorized read.
Other authentication, service-permission, workspace-grant and shared-context failures may occur before these source branches. Their exact deployed envelopes are not asserted here. The descriptor’s generic labels do not make these illustrated messages stable machine codes.
Verify the result
Confirm schemaVersion and returned workspaceId/organizationId against the intended resource. Check all five data groups and record exportedAt; concurrent collections are not a single atomic snapshot.
Protect the returned private export. Inspect redaction/exclusions rather than assuming a complete backup or safely shareable output.
Recovery boundary
A read collection has no compensating data action. On failure, preserve the response and selected context; reconcile any shared resolver initialization separately. Correct authorization/scope before a new authorized read.
Source and limits
Reviewed against Topolo-io/TopoloDevelopers@7b89bd3b39092cdc29f87540847bf99a243f0a40:apps/api/functions/api/developer-console/workspace-data-routes.ts and the application action declaration at 7b89bd3b39092cdc29f87540847bf99a243f0a40. Shared context, workspace access and response wrappers were reviewed at the same revision. The retained data-protection test source was read for its fixtures only; it was not imported or run. Source/declaration association is not proof of serving runtime, completed provider effects or automatic Knowledge invocation.
Change log
- 2026-10-23: Documented this action’s exact schemas, source behavior, conditional complete request/response examples, authorization, verification and recovery limits. Distinguished source behavior from misleading catalog shortcuts. This records a documentation change, not an executed data operation.