Choose the public surface
An app's internal operations can change with its implementation. Publishing an operation creates a customer contract with a separate release decision. Mark a resource or authored operation with external: { "stability": "stable" } in the app manifest's api block.
Select each public field with api: true in its FieldSpec. This applies to resource fields and to an authored operation's request and response fields. Declared nested object fields also need their own api: true. New internal fields remain private until explicitly selected and released.
For example, this manifest declaration publishes an authored query:
{
"api": {
"operations": {
"ReadMetrics": {
"kind": "query",
"description": "Read the number of open tickets.",
"external": { "stability": "stable" },
"input": {
"queue": { "type": "string", "api": true }
},
"output": {
"count": { "type": "number", "api": true }
}
}
}
}
}Implement the matching ReadMetrics handler in the app's api.ts. With the assigned namespace helpdesk, this operation is published as
apps.helpdesk.ReadMetrics. Use that name over HTTP or MCP. The handler and
internal app calls continue to use helpdesk.ReadMetrics. Publishing the manifest does not create the handler or grant credentials access to it.
Validate and release
Validate the app and review the external schema before saving the release. A required input field cannot be kept private: callers need every required input to invoke the operation. Validation refuses such a contract rather than exposing that field automatically.
Saving a release makes its approved public contract available to authenticated discovery and workspace OpenAPI generation. Draft changes remain internal. Existing keys and MCP grants still need approval for any newly added operations or resource access.
Copied and installed apps start with their own publication boundary. Their inherited manifest declarations do not expose an API automatically. Validate and save a release to approve that app's public contract, then choose the operations in the credential's permissions. Discovery uses the frozen contract registered for the current saved version, so later changes to internal schema generators cannot rewrite it.
Evolve the contract
Add optional inputs and compatible outputs while retaining supported behavior. Removing a promised field or operation, narrowing accepted inputs, or widening a response enum can break existing integrations. Publication checks compare against supported released contracts, including contracts added by later app releases.
Rolling an app back cannot erase a contract customers already use. Keep the supported operation available while replacing the underlying feature, or follow the retirement policy with a migration path and at least 30 days of notice for stable contracts.