Extension manifest reference
The repository-root typeroll-extension.json is the source of truth for an
Extension release. Manifest v3 uses these top-level fields:
| Field | Required | Purpose |
|---|---|---|
schema_version |
yes | Must be 3. |
id |
yes | Lowercase namespaced identifier, for example com.example.quotes. |
name |
yes | Human-readable product name. |
version |
yes | Immutable semantic version. |
runtime_compatibility |
yes | Supported Typeroll runtime range. |
distribution |
yes | private, unlisted, or public. |
developer |
yes | Provider name, support URL, and privacy URL. |
permissions |
yes | Requested site scopes with a reason for each scope. |
auth |
no | Optional self-host issuer pairing endpoint. |
config_schema |
no | Installation configuration and public/secret fields. |
frontend |
no | Bundled components or embedded applications. |
admin |
no | Provider-hosted admin pages. |
api |
no | Provider-owned API and direct browser-call contract. |
events |
no | Lifecycle subscriptions and signed webhook endpoint. |
data_handling |
no | Personal-data, location, and retention disclosures. |
Frontend entries
Section titled “Frontend entries”A bundled_component declares HTTPS script_url and script_sha256, plus an
optional style URL and matching hash. An embedded_app declares a frame URL
and only the sandbox capabilities it needs. Each component can define a JSON
schema for editor props, a restricted url_context declaration, and optional
form_bindings:
{ "id": "calculator", "label": "Quote calculator", "render_mode": "bundled_component", "form_bindings": [{ "id": "lead", "form_id": "quote-leads" }], "entry": { "script_url": "https://releases.example.com/quote/1.0.0/index.js", "script_sha256": "…" }}Binding IDs are local to the component and are the names passed to
context.forms.submit(). A binding can target only the fixed form ID declared
in the immutable manifest version.
Installation configuration
Section titled “Installation configuration”config_schema is an object schema whose properties become installation
settings. Mark a property public: true only when the browser component needs
it; public values are embedded in preview and static build snapshots. A
property with format: "secret" is encrypted at rest, never returned by read
APIs, cannot be public, and cannot define a default.
Use enum for a constrained value and a same-length enum_labels array for
human-readable choices in the portal. Stored values remain stable identifiers:
{ "type": "object", "additionalProperties": false, "properties": { "audience": { "type": "string", "title": "Audience", "enum": ["consumer", "business"], "enum_labels": ["Consumers", "Businesses"], "public": true } }}Configuration updates merge declared keys into the existing installation. Omitted properties preserve their current values, including masked secrets. Because public config is build-time data, a config update requires a new site deploy. The developer CLI and MCP tool queue that deploy by default.
Available scopes
Section titled “Available scopes”content:read,content:writecollections:read,collections:writeforms:read,forms:submit,forms:writesubmissions:readmedia:read,media:writedeploy:requestextension:config:read
The effective permission is the intersection of the manifest request, the site administrator’s grant, and the current Typeroll user’s permission. The portal rejects unknown scopes and routes.
forms:submit is deliberately narrower than forms:write: it permits a
component to submit to its declared bindings, but cannot create or edit forms
or read submitted data.
Direct provider API
Section titled “Direct provider API”api.base_url is the provider-owned HTTPS endpoint. Routes declare a path
pattern and allowed HTTP methods. Paths are relative to api.base_url.
authentication is signed_installation by default or none when the
provider uses only its own public authentication. These declarations constrain
the Typeroll runtime but do not replace provider-side authorization or CORS.
Routes are unavailable in editor preview unless they declare
preview_methods. That array must be a non-empty subset of the route’s
ordinary methods. Expose only read-only or otherwise harmless operations:
{ "path": "/quotes/*", "methods": ["GET", "POST"], "preview_methods": ["GET"]}The runtime enforces this allowlist before sending a request. The signed
preview token repeats the allowed routes, and the provider must enforce those
claims server-side too. A preview token has preview: true; its origin claim
and the opaque preview frame’s browser Origin header are both null, so
their equality alone does not establish a trusted site origin.
Typeroll never proxies these routes. The direct runtime always omits browser
credentials and rejects redirects. A signed installation token, when enabled,
uses X-Typeroll-Extension-Token and contains no visitor identity.
Version lifecycle
Section titled “Version lifecycle”draft: editable and available to its developer organization.review: queued for hosted public-catalog review.published: immutable and installable according to its distribution.deprecated: existing timeless installations may keep using the release, but new installs are blocked; a newer compatible release is selected automatically when available.revoked: the release is excluded from selection and catalog availability. The installation falls back to another compatible release when possible; otherwise its tokens, admin launch, and frontend are unavailable without blocking the rest of the site build.
Download the complete
typeroll-extension-manifest-v3.schema.json.
The published file is generated from the same schema used by the portal.
For production self-hosting variables and key rotation, see Self-Hosting.