Skip to main content
Managed capabilities let a hosted Pages site use a small set of AI, retrieval, and image operations without receiving a provider credential. You define an account policy, optionally narrow it for a project, and grant an exact set of operations to one site. Goosy stores the site’s runtime credential and never returns its secret in an API response.
This page documents the request contracts. Deployment and account exposure are separate, so an environment may refuse these tools while its rollout, migration, or exposure switch remains closed. Use the catalogue response as the source of truth for the operations available to your account.

Before you configure a site

Use an ordinary workspace-scoped API key whose holder currently has Use the API and MCP and Manage Pages. Managed policies and grants can only narrow that access. They cannot add a permission the key holder does not have.
Every tool on this page uses the same endpoint shape:

Discover the available operations

Call pages.capabilities.catalogue before creating or changing a policy. With an empty body, it returns the managed operations and writing tiers installed in the current environment.
Each operation reports its leverage, whether it requires confirmation, whether it supports a standing approval, the writing tiers it accepts, and its exact managed_key_input_schema. That schema is generated from the same validator used by the managed dispatcher. The catalogue exposes only operations with an installed managed dispatcher; do not build an allowlist from names that are absent from this response. To inspect the effective policy for one site, include its target:
The response’s effective object contains the active grant and the intersection of its account policy, optional project policy, and site grant. This abridged response omits the operation’s machine-readable input schema:
The tier names in this example are illustrative catalogue values. Read writing_tiers and each operation’s writing_tiers rather than hard-coding a tier list.

Configure the policy and site grant

pages.capabilities.configure always uses an exact two-call confirmation. The first call proposes one configuration and makes no change. The second call must repeat that same configuration and add the returned confirmation_id. Post each JSON example below with the ordinary admin key:

1. Create the account policy

Send a policy configuration. An account policy uses null for both workspace_id and project_board_id.
The proposal returns state: "confirmation_required", a confirmation_id, and expires_in_seconds. Repeat the complete object and add that id at the top level. A successful confirmation returns state: "configured" with policy_id, version_id, version, activated, and request_replayed.

2. Optionally add a project policy

A project policy uses scope_kind: "project" and supplies its exact workspace_id and project_board_id. It can narrow the account policy’s operations, tiers, or limits. Save its returned policy_id for the grant.

3. Grant the site a narrower capability set

Reference the active account policy and, when used, the active project policy. target_board_id is the board on which the site’s managed image operations may act.
rate_cap is optional. Omit it or send null and the grant carries no per-window request cap. Send both fields together — a count without a window and a window without a count are each refused. The window does not roll: it runs in fixed spans of window_seconds counted from the moment the grant was issued, so the reset is an exact time rather than “when your oldest call ages out”. A call that would exceed the cap is refused with managed_request.grant_request_rate_exceeded, and the refusal names the cap, the window, and the exact moment the window resets, so an unattended runtime can wait rather than retry blindly. Confirm the exact grant in a second call. A ready site enrollment returns grant_saved: true and runtime_credential: "ready"; it does not return a key or secret. state: "enrollment_pending" means the grant was saved but one of the writes that hangs off it — the runtime credential, the standing approval, or both — needs a retry with the same confirmed request. Read runtime_credential and standing_approval to see which. The confirmation is NOT consumed in that state, and every write behind it is idempotent, so repeating the same confirmation_id completes the missing half without re-creating the grant or minting a second approval. Confirming a site grant also creates its standing approval. Every granted operation that reports supports_standing_approval is covered by one approval minted with the grant, so the site’s own key runs unattended from its first call rather than being asked to confirm each one. The confirmed result reports standing_approval: "ready" with standing_approval_id; "not_required" means no granted operation needs one, and "pending" means the grant saved but the approval did not — the response comes back as state: "enrollment_pending", the confirmation is left unconsumed, and repeating the same confirmation_id mints it. Until it exists the site’s key is answered confirmation_required on every confirmation-classified operation, so a "pending" is worth retrying before you publish. The approval’s disclosure is generated from the grant’s own limits and rate cap, and it carries no expiry of its own: revoking the grant revokes it. Limits are intersected at request time, and the narrowest current value wins. Lowering or disabling a policy therefore stops later work even when a site has an older grant.

Standing approvals

A standing approval lets an unattended integration run an operation whose registered declaration normally requires confirmation. It remains bound to one grant and does not bypass the caller’s live permissions, the active policies, credits, meters, or request limits. A site grant already has one. Confirming a site grant mints it, so you do not need this call to make a linked site key work. Use it to change the terms of the approval a grant already carries — a shorter expiry, or a binding to a standing automation. Replacing the approval replaces those terms for the same grant.

Enroll an exact workflow version

A managed workflow uses two grants. The site grant permits workflow.invoke and workflow.status. A separate workflow grant permits only the managed operations that its steps call. Create the workflow grant through the same two-call flow, targeting one active, published definition version:
The workflow version must contain only bounded managed.native_tool steps. Each step declares a supported operation and its own ceilings. Managed workflows do not accept delay, conversation, code, or other side-effect nodes, and a managed step cannot call workflow.invoke or workflow.status. Create two standing approvals for the same native standing automation: one on the site grant and one on the workflow grant. Set standing_automation_id on both approvals. Then enroll the exact pair through the same two-call configure flow:
The configured response includes enrollment_id, workflow_definition_id, workflow_definition_version_id, service_actor_user_id, service_actor_role, and request_replayed. Goosy derives those workflow and actor bindings from the native enrollment. The site’s managed key is never passed to the workflow runtime.

Call a managed operation

Calls originate from the site’s server runtime using its reserved GOOSY_API_KEY binding. This is distinct from the ordinary admin key used to configure the site. Keep the managed binding out of browser code, source archives, logs, and public previews. It selects the tenant, workspace, site, board, and grant; operation bodies cannot override them. Goosy manages it and does not return it through the configuration API. Read the API origin from env.GOOSY_API_BASE, never from a constant in your code. Goosy binds it beside GOOSY_API_KEY on every publish, and its value is your own site’s origin plus /__api — a reserved path we answer above your code, which forwards the call to the platform this site is actually published on. A hard-coded https://app.goosybear.ai sends a site running on a preview or a staging environment straight to production with production data — which is why the name is reserved and you cannot set it yourself. Build the URL as ${env.GOOSY_API_BASE}/api/v1/tools/{operation}; the absolute URLs on this page show the platform host for reading. The full contract for that path — what it forwards, what it refuses, and what it adds — is Calling the platform from your Worker. Read-classified operations require an idempotency_key. An operation that requires confirmation follows one of two paths:
  • Without a standing approval, send the operation body without an idempotency_key. The response contains state: "confirmation_required". Confirm it by calling the same operation with only confirmation_id; the stored request is used.
  • With a verified standing approval, send the body with an idempotency_key. The request runs without an interactive confirmation. A site key on a confirmed site grant is in this case already: the approval was minted with the grant, and the grant’s limits and rate cap are what bound the work.
An idempotency key identifies one exact request. Reusing it with different input is refused. Reusing it with identical input returns the durable request state and does not submit the provider work again. Keys are trimmed, nonempty strings of at most 256 characters.

Exact operation bodies

Send each body to POST ${env.GOOSY_API_BASE}/api/v1/tools/{operation} — on a published site that resolves to https://your-site.example/__api/api/v1/tools/{operation}, which we forward to the platform. The operation’s managed_key_input_schema in pages.capabilities.catalogue is authoritative for runtime enum values, bounds, defaults, and request controls. Only pages.ai.generate_text accepts tier and requestedOutputTokens. The other nine operations reject both fields.
images.generate and images.iterate also have ordinary API-key contracts. A site-managed credential is intercepted before those ordinary tool bodies and accepts only the managed schemas below. Do not send an ordinary workspace, board, brief, or provider field from managed site code.

pages.ai.generate_text

Choose tier from the operation’s current catalogue entry, or omit it to use the grant’s current default. requestedOutputTokens is required on the initial call and must be a positive integer within the effective limit.
The operation response is { "text": "..." } inside the managed execution envelope.
maxResults defaults to 5 and is bounded from 1 through 10. The result contains an answer when available, normalized result records, a truncation flag, and filters the provider could not apply.

web.read

Only HTTP and HTTPS URLs are accepted. The result contains the URL, optional title, Markdown content, and a truncation flag.
maxResults defaults to 5 and is bounded from 1 through 10. Keep the managed response’s request_id; acquisition refers back to this succeeded search rather than accepting a public image URL.

images.acquire_remote

The search request must belong to the same tenant, workspace, and grant. The result contains storageObjectId and boardItemId for the copy attached to the site’s granted board.

images.generate

count defaults to 1. Its upper bound and accepted aspect ratios are published by the generated request schema. The result contains runId and deliveredIds.

images.iterate

The parent generation must already belong to the exact board selected by the site grant. The result contains runId and deliveredIds.

workflow.invoke

workflow.invoke requires an active workflow enrollment and both of its standing approvals. It runs the enrolled, pinned workflow version synchronously to a terminal result; an enqueue or accepted state is not reported as success.
The managed response contains workflowRunId and status: "completed". A failed child step fails the invocation. An uncertain paid child or terminal write returns an uncertain managed request for reconciliation and is not automatically replayed.

workflow.status

Use the managed request id returned by workflow.invoke to read its durable native run state:
The response contains workflowRunId, status (active, completed, or abandoned), and completedAt when the run has ended. The lookup remains bound to the same tenant, workspace, and site grant.

connections.call

Make one request with a connection this site has bound by name. Bind a connection in the site’s settings drawer (Secrets → Connections this site calls); its name there is the name your code sends. The request goes to that connection’s own host, signed in with the connection’s credential, which never reaches your site:
method is GET, HEAD, POST, PUT, PATCH or DELETE; body is JSON and is never sent on GET or HEAD; headers never carries a credential, Host, Cookie or Idempotency-Key. There is no host field: the host is the connection’s. The response is { connection, host, status, data }, data being the provider’s JSON answer. A name the site has not bound answers binding_not_found, and a connection the site’s brand can no longer use answers connection_not_found, before anything is sent. The host must be on the workspace’s list of hosts automations may call. Only a site’s own key reaches this operation: its grant must name the site and list connections.call, which a site’s grant gains when the site binds its first connection. Any other key, an MCP client included, is refused operation_unavailable. Binding the first connection refreshes the site’s GOOSY_API_KEY, so publish the site after binding it. A request that changes something on the provider’s side is not repeated by Goosy; one that timed out returns uncertain.

Handle execution states

Managed execution returns one of four states inside data: Example confirmation response:
Confirm an execution operation with only the id:
The stored payload, output reservation, and selected writing tier are used; fields sent beside confirmation_id do not replace them. Configuration confirmation is different: pages.capabilities.configure requires the exact configuration again.

Bringing your own provider key instead

Managed capabilities exist so a site never holds a provider credential. If you would rather your site call OpenAI (or any other provider) on your own account, you can: declare the key’s NAME in bindings.secrets in pages.deploy.json, add the key in the site’s Secrets band in Goosy (Add a key), and your Worker reads it as env.<NAME> and calls the provider with an ordinary fetch. A key with a host can instead be bound as callable, so your Worker calls it by name through its managed key and the value never enters the Worker. There is no customer-API endpoint that sets a secret’s value today — a value is typed only in the site’s Secrets band or on the Connections page, and the Goosy agent’s page.set_site_secret verb gives a site a key the brand already holds. See Setting a secret’s VALUE. The trade is the one you would expect: your key, your provider bill, your rate limits, and no policy, grant, or credit metering around the call. A managed operation is the other side of that trade.

Credits and request limits

When a managed call is billable, it uses the account’s existing credit balance and the operation’s native meter. Managed access does not create a separate wallet. Admission checks the current balance, the effective input, output, search, tool-call, and concurrency limits, and the grant’s per-window request cap before dispatch. The execution service records actual usage through the operation’s normal settlement path; the policy values are limits, not prices. See Actions that spend credits for the general confirmation model and credits.balance precheck.

Revoke access

Revoke the managed grant through pages.capabilities.configure. This is also an exact two-call confirmation:
Repeat the same configuration with confirmation_id. The configured result reports changed, standing_approvals_revoked, managed_keys_revoked, and request_replayed. To revoke only one standing approval, use: