collectPayment, sendEmail); the runtime owns how it happens (Stripe Connect, the transactional email gateway, object storage). You never touch a third-party SDK or hold a vendor API key.
A first invocation
Here is a CTA button on a page wired to open Stripe Checkout for a plan:page.json
collectPayment by name with required args. When a user clicks the button, the runtime validates the args against the capability’s input schema, dispatches to Stripe through the workspace’s Connect account, and hands back a checkout_url for the page to redirect to. No SDK import, no API key in the page, no provider-specific code.
The catalogue
Six capabilities ship with every workspace. Each has a uniqueid, a semver version, a typed input and output schema, and a backend that is either auto-provisioned or guided through onboarding.
How the runtime dispatches a call
When a block fires a capability, three things happen before any provider code runs:Binding a capability to a block
Most capability calls live inside a block prop — typicallyon_click, on_submit, or data_source. The block declares which capability to call and what arguments to pass; the runtime evaluates form-field references against the submitted data before dispatch.
form-block.json
args against sendEmail’s input schema before dispatching. Invalid arguments return an error envelope — the capability never fires.
Across the iframe boundary
When a tenant page is embedded as an iframe (for example, on a marketing site), capability calls cross the iframe boundary via a postMessage bridge. The bridge serializes each call to the edge proxy at{tenant}.gavai.run/_capability, which forwards to the runtime. You do not write this plumbing — it is automatic.
Versioning
Capabilities use semver. A page document can pin a capability version so a future v2 doesn’t break it:pinned-version.json
version uses the latest stable version of that capability.
The error envelope
Every capability failure returns the same envelope so a block can handle errors uniformly regardless of which capability failed: Input-schema violations always usecode: "invalid_input" and include a field-level details object describing which fields failed and why. Each capability page enumerates its other error codes.
Custom capabilities
Custom capabilities are on the roadmap. Workspaces cannot yet register arbitrary capabilities. Webhook-backed and runtime-bound capability handlers are coming — treat custom capabilities as “coming soon” until the roadmap ships.