Integrations

Connections, grants, provider operations, webhooks.

Raw Markdown for agents: integrations.md. MCP: read_guide("integrations").

Integrations connect external systems (shops, CRMs, mail, accounting, databases) to the tenant. Three objects matter:

  • A connection holds the credentials of one external account. It always belongs to the user who created it; only that user can call operations through it.
  • A grant allows one connection inside one Space: which provider operations may run there, with optional constraints. Skills, workflows and agents working in a Space use grants.
  • A provider operation is a call to the external system, registered as integrations.<provider>.<resource>.<operation> (for example integrations.shopify.orders.list). Every call is recorded as an invocation.

Flow

  1. Find the provider operations. search_operations(provider="shopify") lists the operations of one provider; by default search only shows providers with a connection in the tenant, pass connected_only=false to see all. integrations.catalog.get describes a provider: contract_digest, auth schemes, and per operation the input schema, risk_level, requires_space and constraint_policy.
  2. Check the connection. get_context lists the caller's connections with provider, connection_id and the number of active grants. integrations.connections.get shows status and setup state. Without a connection, integrations.authorizations.begin starts one; OAuth schemes return an authorization_url the user must open in the browser (offer it through the app, do not paste it into a message). Some providers need a setup step afterwards (integrations.connections.setup_options, then integrations.connections.complete_setup).
  3. Create a grant with integrations.grants.create: connection_id, space_id and allowed_operations with full operation keys. integrations.grants.list shows existing grants; change one with integrations.grants.update instead of creating a second grant for the same connection and Space.
  4. Call the operation with invoke. Arguments are the provider fields from describe_operation plus connection_id; operations inside a Space also take space_id and grant_id. Operations with requires_space always need them; others can be called without a Space only when the provider allows direct owner use. Queued operations return an invocation_id; poll integrations.invocations.get.
  5. Webhooks. Provider webhooks are not created by hand. When skills.automation.set stores a webhook with auth: integration and mode: subscription, the platform creates the provider subscriptions for the listed events through the grant in grant_id. This happens asynchronously: skills.automation.get shows subscription_state pending until the provider confirmed and active afterwards. A subscription that already exists at the provider for the same event and address is adopted, not duplicated. The grant must allow the provider's webhook subscription operations.

Rules

  • Operation keys are always full keys: integrations.shopify.orders.list, never orders.list or shopify.orders.list.
  • Every operation with risk_level irreversible in allowed_operations needs risk_acknowledgements[<operation key>] set to the provider's contract_digest. Ask the user to confirm the risk before you set it.
  • A grant belongs to exactly one connection and one Space. The connection must belong to the caller and the caller must have access to the Space.
  • safe_constraints has the form {"version": 1, "constraints": {<operation key>: {<field>: {<rule>: <value>}}}}. Only fields and rules listed in the operation's constraint_policy are accepted (allowed_values, max_length, maximum, maximum_items, minimum, required_value).
  • asset_boundaries narrows a grant to part of the connection's setup selection; it cannot add values the setup did not select.
  • Errors raised by the platform itself carry a message, details with the offending path and a hint: grant validation, input validation, missing permission for an operation, missing risk acknowledgement. Errors that come from the provider or the runner (timeouts, rate limits, provider rejections) only carry their code; the provider's own text is never passed through.

Errors and what to do

CodeWhat to do
integration_grant_policy_invaliddetails names the entry, for example allowed_operations[2]; the hint shows the expected key format and the closest valid key. Fix that entry and retry.
integration_invalid_inputdetails lists each invalid argument path; unknown parameters list the allowed ones. Compare with describe_operation.
integration_operation_not_allowedThe connection exists but may not run this operation here: the grant does not allow it, space_id/grant_id are missing, or the setup does not offer it. Extend the grant with integrations.grants.update or ask the Space owner.
integration_risk_acknowledgement_requireddetails has operation and contract_digest; set risk_acknowledgements[operation] = contract_digest after the user confirmed.
integration_setup_requiredFinish the connection setup with integrations.connections.setup_options and integrations.connections.complete_setup.
integration_not_foundThe connection, grant or Space does not exist for the caller, or belongs to someone else. Check the ids in get_context and integrations.grants.list.

Example

Grant a Space read access to Shopify orders, at most 50 per page:

{
  "operation_key": "integrations.grants.create",
  "arguments": {
    "connection_id": "<connection uuid>",
    "space_id": "<space uuid>",
    "allowed_operations": [
      "integrations.shopify.orders.list",
      "integrations.shopify.orders.get"
    ],
    "safe_constraints": {
      "version": 1,
      "constraints": {
        "integrations.shopify.orders.list": {"limit": {"maximum": 50}}
      }
    },
    "idempotency_key": "grant-shopify-orders-<space uuid>"
  }
}

Then list paid orders through that grant:

{
  "operation_key": "integrations.shopify.orders.list",
  "arguments": {
    "connection_id": "<connection uuid>",
    "space_id": "<space uuid>",
    "grant_id": "<grant id from the response>",
    "query": "financial_status:paid created_at:>2026-09-01",
    "limit": 50
  }
}

En esta página