> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tied.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Current marketplace contracts

ENG-5375 documents the nine existing catalogue, action, request, generated-definition and tenant overlay operations. These are current HTTP contracts, not approved MCP tools or SDK exposure. The [proposal](https://github.com/TiedInc/Tied/blob/main/docs/platform-api/proposals/ENG-5375.json) remains unapproved, MCP-hidden and SDK-excluded. Dispatch, synced records, activity and connections are separate surfaces. None of these nine operations dispatches an action. Connected-app credentials are held by the integration provider and are not returned by any operation.

| Operation | Account role | Data source |
| - | - | - |
| GET catalog | Any member | Global presentation catalogue; not connect allowlist |
| GET actions | Administrator | Global code registry, no tenant overlay |
| GET action\_catalog | Administrator | Tenant overlay, manual path, current account connections |
| POST requests | Any member | IntegrationRequest on caller account/user; super-admin demand view |
| GET tool\_definitions | Administrator | Same overlay registry and tool generator, active connections, agentic path and auto approval |
| GET settings | Administrator | Stored provider settings and action overrides only |
| PUT settings/provider/:provider\_config\_key | Administrator | Provider allowlist validation; account-scoped upsert |
| PUT settings/action/:action\_key | Administrator | Code registry validation; account-scoped upsert |
| DELETE settings/action/:action\_key | Administrator | Account-scoped stored override deletion |

The route account requires authenticated membership. Nonmember and policy denials currently use 401 with `error`; unauthenticated token/session requests use 401 with `errors`. These are not a standardized 403 contract. After authentication and account membership, the inherited trial-expired lock refuses all four writes with 402 before action-specific authorization, input validation or persistence. GET operations remain available to their authorized roles. The exact refusal body is `{"error":"trial_expired_locked","message":"This workspace trial has ended. Restore billing from the billing page to continue."}`; no marketplace records change and no cleanup job is queued. Global catalogue/registry data is shared code data; tenant settings, requests and connections are scoped through `Current.account`.

`action_key` retains dots in a single slash-free path segment, for example `synthetic.read`. Provider keys also use a slash-free segment. Action catalogue pages default to 1/25, cap page at 10000 and page size at 100; malformed values and wire query arrays (`page[]=2&per_page[]=1`) normalize to defaults. An out-of-range page returns an empty actions array and nullable `next_page`.

## Declared and effective trust

The actions list reports `policy_status: declared` and each action’s `key`, `name`, `label`, nullable `description`, `mutates`, `available_to_agent`, and `trust`. The trust block contains `trust_class`, `approval_tier`, nullable `approval_policy`, `reversible`, nullable `compliance_class`, `pre_action_narration`, and `emit_receipt`. A declaration is not evidence of dispatch enforcement. The global actions list never reflects tenant overrides.

The manual action catalogue projects `app_id`, `action_key`, `label`, nullable `description`, `mutates`, `input_schema`, effective `trust_class` and `approval_tier`, and `needs_reconnect`. Retained expired/revoked/errored connections remain here with `needs_reconnect: true`; absent connections do not appear. User-scoped connections belong to the requesting member.

Generated definitions are read-only pairs of a standard `mcp_tool` (name, title, optional description, inputSchema, annotations) and the full internal `trust` block. Trust additionally carries code fields such as class, approval policy when declared, rate limit, idempotency key, action/app identity, kind, nullable provider key, connection scope, paths and schema version. The generator filters disabled/manual-only/non-auto actions and requires an active connection or enabled hook. It supplies no entitlement collaborator today. This endpoint is not an MCP transport, has no invoke route, and never executes tools.

## Overlay boundaries today

No provider row resolves to `summary` and `org`. `GET settings` returns only stored rows, not effective defaults. A flat provider PUT permits `sync_depth` (`summary` or `full`) and `connection_scope` (`org` or `user`). Choosing full widens data retention beyond summary; a persisted full-to-summary transition queues cleanup. Connection scope is stored but inactive and does not rescope existing connections.

A flat action PUT permits `disabled`, `manual_only`, nullable `approval_tier` and nullable positive integer `rate_limit`. Code approval tiers order `none`, `notify`, `single_approver`, `dual_control`; a supplied tier cannot fall below the code tier. A supplied rate cannot exceed the lower of the code rate and service default. The overlay registry clamps these two axes against code on reads. Disabled removes the definition; manual\_only removes its agentic path. Action identity, schema, dispatch binding and other trust fields come from code.

These checks compare against code, **not the preceding tenant value**. Resetting disabled/manual\_only to false, clearing rate\_limit to null, lowering a previously tightened approval tier toward code, or deleting a stored override can widen the effective tenant policy. DELETE restores code defaults. Current tests prove these accepted resets and reject limits above code. This is not a monotonic tighten-only promise.

Body `account_id` and `user_id` do not select ownership. Unpermitted fields are ignored. Controllers permit flat fields: JSON wrapping of flat requests does not make nested-only `settings`/`request` envelopes a supported input. Nested-only settings writes leave existing fields/defaults unchanged; a nested-only integration request fails required app-name validation. Contract tests pin these behaviors.

## Requests and errors

Request creation stores `requested_app`, optional website/urgency/note, caller account and caller user. A valid catalogue key wins; otherwise app\_name is squished, case-insensitively matched to catalogue names, or stored as typed. Unknown catalogue keys fall back to typed app\_name. Urgency accepts `nice_to_have`, `this_quarter`, `blocking`; requested\_app is required, maximum 100 characters, website 255, note 2000. The 201 body has id, requested\_app and created\_at. No integration is connected by submission.

Unknown `integration_app_id` returns an empty 200 actions list. Missing integration\_app\_id is 422. Unknown provider/action overlay writes are 422 with a single human-readable `error` sentence; invalid overlay enum/rate fields also return one error sentence. Request validation instead returns `message` and `attributes` containing invalid attribute names. A missing stored override on DELETE returns 404. There is no field-level error object. [ENG-5874](https://linear.app/tied/issue/ENG-5874) and [ENG-5831](https://linear.app/tied/issue/ENG-5831) track the missing consistent unknown-provider/validation behavior. This documentation makes no future validation guarantee.

## Evidence

`spec/contract/marketplace_spec.rb` performs persisted Rails integration requests in an isolated database using authenticated synthetic administrators/members. The catalogue and registry are synthetic collaborators; controller responses, policies, database associations, serializers and generator are real. No real provider descriptions, credentials or customer data are used. Tool-list tests assert that neither dispatch service nor dispatcher nor network is called.

Capture records under `docs/platform-api/marketplace-evidence` contain method, route template, status, JSON body (null for empty 204), synthetic provenance and exact fixture/helper/controller and inherited trial-lock source hashes. The capture guard rejects non-JSON responses before any write. Headers, auth tokens and cookies are omitted. The importer checks provenance, every capture checksum and source freshness before importing examples. It validates all JSON bodies with OAS 3.0 semantics, including nulls. These are synthetic running Rails request captures, not production traffic or provider conformance evidence.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.