Outcome
Inspect saved capability schemas, pricing and synchronization metadata without executing or synchronizing a P2P provider.
GET /api/developer-console/apps/{appId}/p2p-capabilities
Before you start
Use the original authenticated organization with the published Developers apps:read permission. Discover an accessible canonical Developers workspace and bind it separately as resource context. Input appId is an accessible developer app record identifier; it is not a workspace id or an access grant.
The concrete route allows suspended developer profiles to read but denies revoked access. It resolves a developer profile and verified workspace, then requires app read access in that workspace. Platform authority, organization administrator status, app membership and developer ownership are distinct source branches; an app outside the selected workspace or invisible to the actor returns404. Do not broaden the organization or grant after a refusal.
These are saved app configuration reads, not a live P2P provider discovery result or a downloadable/installable mobile catalog. Publication and saved sync flags do not grant caller access, install an app or authorize a provider execution.
The shared request path can insert a local identity-only workspace mirror and, for an enabled organization without a developer profile, create the initial developer profile after resolving a platform-issued workspace. This can precede app access refusal. No canonical Auth workspace is minted, and readOnly metadata is not a promise of zero initialization writes.
All worked responses are source-derived synthetic UNRUN examples. No real developer app, declaration, provider, key, person, private record, publication or other business action was read or changed. The immutable source matches the retained declaration revision; serving-runtime adoption is not independently proven.
Request
Action: app_topolo_developers.apps.p2p_capabilities.list.
{
"appId": "app_docs_fixture"
}
These identifiers are fictional; discover the actual app and separately bind its canonical Developers workspace. Validate and plan with the current published schema before any real call.
Response and behavior
HTTP200 uses the full envelope {success:true,message,data:{...}}. Read records inside data rather than assuming the top-level response is the collection. Exact JSON schemas below are copied from the current declaration, whose structural permissiveness does not substitute for the source-qualified field meanings.
The shared context first authenticates and finds or initializes a developer profile; a revoked profile is refused and a suspended profile is allowed for these GET handlers. For an ordinary same-organization request, Auth verifies the requested workspace at minimum read level. The existing privileged cross-organization platform context instead uses the seeded developer profile’s workspace and does not honor a requested workspace header on that branch. Both branches still reach the app-workspace match and actor.canRead checks. The app-specific handlers do not require completed onboarding for reads. Missing and inaccessible app records are deliberately indistinguishable404 responses.
App access is evaluated after workspace selection. In the source actor calculation, recognized platform access can produce owner role, an organization mismatch otherwise denies, an administrator of the owning organization is an owner, explicit matching user id/email membership can supply a role, and matching developer ownership is the fallback. A permission string alone does not establish all these context conditions.
The selected list query reads saved app metadata without contacting P2P, fetching an artifact URL, installing code, publishing a declaration, minting a key or sending a notification. Shared mirror/profile initialization remains a separate possible effect; do not delete those records as automatic rollback.
Success returns data.capabilities. The query selects all developer_app_p2p_capabilities rows with the selected app_id, ordered updated_at DESC then created_at DESC. It has no LIMIT, cursor, search, status filter, directory-visibility filter or deterministic id tie-breaker. All stored declaration statuses are included; a list result is not a list of currently available P2P providers.
Input requires appId. Only that app selector is used; extra empty-schema keys from the generic declaration are not pagination, filtering or provider-execution controls. The mapper returns capabilityId,appId,developerId,publisherOrgId,name,description,category,inputSchema,outputSchema,pricingModel,pricingAmountMinor,currency,requiresHumanApproval,supportedContexts,trustLevel,publicDirectoryVisible,status,sourceRevision,lastSyncedAt,lastSyncError,createdAt,updatedAt. There is no workspaceId in this row projection.
Schemas and supportedContexts are JSON-parsed metadata with fallbacks. Pricing amount is converted with Number and boolean flags use a numeric1 check. Defaults such as free/standard/draft and mapping-time timestamp fallback do not prove provider validity, a price quote, trust certification, schema/example correctness or sync readiness.
requiresHumanApproval and publicDirectoryVisible are declaration attributes, not an approval receipt or current directory membership. lastSyncedAt and lastSyncError describe saved sync metadata only. This GET does not run the sync eligibility helper, call P2P, authorize metered work, settle payment or verify a provider result. Use separately discovered current P2P contracts for any independently approved operation.
Worked responses
One saved draft configuration record
Complete source-derived synthetic UNRUN HTTP200 after all context/app checks succeed. Exactly one fictional saved draft record is present. It is not an execution, approval, provider result, download or install.
{
"success": true,
"message": "P2P capabilities fetched successfully",
"data": {
"capabilities": [
{
"capabilityId": "cap_docs_fixture",
"appId": "app_docs_fixture",
"developerId": "dev_docs_fixture",
"publisherOrgId": "org_docs_fixture",
"name": "Summarize fixture text",
"description": "A fictional saved capability declaration.",
"category": "text",
"inputSchema": {
"type": "object",
"properties": {
"text": {
"type": "string"
}
},
"required": [
"text"
],
"additionalProperties": false
},
"outputSchema": {
"type": "object",
"properties": {
"summary": {
"type": "string"
}
},
"required": [
"summary"
],
"additionalProperties": false
},
"pricingModel": "free",
"pricingAmountMinor": null,
"currency": null,
"requiresHumanApproval": true,
"supportedContexts": [
"human",
"agent"
],
"trustLevel": "standard",
"publicDirectoryVisible": false,
"status": "draft",
"sourceRevision": "rev_docs_fixture_unrun",
"lastSyncedAt": null,
"lastSyncError": null,
"createdAt": "2026-10-21T08:00:00.000Z",
"updatedAt": "2026-10-21T08:00:00.000Z"
}
]
}
}
Inspect the actual saved record in the original context; draft metadata authorizes no subsequent operation.
A successful empty collection
Complete synthetic UNRUN HTTP200 after successful auth/workspace/app checks and an empty successful database query. This is not a dependency failure or missing/inaccessible app.
{
"success": true,
"message": "P2P capabilities fetched successfully",
"data": {
"capabilities": []
}
}
Retain the scoped empty collection; do not create a record or change access to make it nonempty.
App not visible in this workspace
Complete synthetic UNRUN HTTP404 after shared context resolution for a missing app or workspace/actor mismatch. This deliberately does not distinguish inaccessible from absent data. Initialization can already have occurred.
{
"success": false,
"error": {
"message": "Developer app not found"
}
}
Preserve actual refusal/request id and original scope; do not try another organization, guess identifiers or broaden grants.
Verify and recover
-
Use data.capabilities[].capabilityId, appId and publisherOrgId; compare the original app and context. Distinguish the declaration’s provider id from the authority to call that provider.
-
Treat returned schemas, pricing, visibility, approval and synchronization fields as stored configuration. Inspect current effective provider availability/authorization only through its supported separately scoped discovery, not by executing a sample job.
-
Preserve inconsistent or stale saved metadata for the owner. No automatic sync, publication, deletion, payment, permission expansion or guessed recovery action is part of this list task.
The selected query has no saved-record mutation to undo; shared initialization can still have separate effects. Do not delete a profile/mirror or perform a business operation as an automatic inverse.
Change log
- 2026-10-21: Added complete source-qualified response envelopes, saved configuration field meanings, exact collection/access behavior and synthetic examples. Provider execution, sync, download, installation and production runtime remain separate evidence. Examples are unrun.