# Connect The `connect` section of a marketplace manifest JSON corresponds to the values on the **[Connect](/docs/build-flow/connect/)** page in the app build flow. It defines how your Zoom app authenticates with third-party applications, integrates external data, exposes REST APIs, registers incoming webhooks, and optionally provides an MCP server. This document describes every field available in the `connect` section, including its data type, whether it is required, and any constraints enforced when the manifest is imported. **Note** - Every field in the tables below is marked **Required**, **Optional**, or **Conditional**. _Conditional_ means the field is required only in specific cases; the cases are stated in the field's own description. --- ## Overview A connector lets a third-party API be used as a set of building blocks inside the Zoom platform — for example, as actions and triggers in workflows, or as tools an agent can call. The `connect` object is where you declare that integration. At a high level, the `connect` object answers four questions: - **How does the connector authenticate to your API?** → the `security` block. - **What APIs can the connector call?** → the `routes` array, where each route is one REST API on your service. - **Does your service need to send events to the connector?** → the `incoming_webhooks` array. - **Does the connector need to call an MCP server?** → the `mcp` block. --- ## Manifest JSON This is a display of the full `connect` schema populated with sample values. You only include the sections your connector actually uses. A connector can be as small as a base URL plus authentication, or as rich as dozens of routes, webhooks, and an MCP server. Everything in the JSON is validated at import time; if any section is malformed, the import is rejected and you'll receive a validation error describing the problem. ```json { "connect": { "enable": true, "url": "https://api.example.com", "security": { "type": 36, "oauth_config": { "authorize_url": "https://app.example.com/oauth/authorize", "access_token_url": "https://app.example.com/oauth/token", "refresh_url": "https://app.example.com/oauth/token", "client_id": "abc123", "client_secret": "s3cr3t", "scope": "read write", "client_authentication": "header", "code_challenge_method": "S256" } }, "routes": [ { "name": "Get the current user", "path": "/users/me", "method": "GET", "key": "example_get_current_user", "description": "Returns the authenticated user.", "parameters": [ { "name": "include", "displayName": "Include", "description": "Related resources to include.", "in": "query", "required": false, "schema": { "type": "string" } } ], "response": { "description": "Current user", "content": "application/json" } }, { "name": "Create item", "path": "/items", "method": "POST", "key": "example_create_item", "request_body": { "required": true, "content": "application/json", "schema": { "type": "object", "properties": [ { "key": "title", "name": "title", "type": "string" }, { "key": "count", "name": "count", "type": "integer" } ] } }, "response": { "description": "Created", "content": "application/json" } } ], "incoming_webhooks": [ { "name": "Item events", "short_description": "Fires on item changes.", "key": "example_item_events", "type": "RestHook", "status": "READY", "state": "ON", "authentication": { "key": "X-Signature", "secret": "whsec_xxx", "algorithm": "HMAC_SHA256", "encoding": "BASE64", "prefix": "sha256=" }, "validation": { "enabled": true, "request_key": "challenge", "response_key": "challenge" }, "rest_hook": { "subscribe": { "route_key": "example_create_item" }, "unsubscribe": { "route_key": "example_create_item" } } } ], "mcp": { "base_url": "https://mcp.example.com/sse", "name": "Example", "ext": { "description": "Example MCP server" } } } } ``` --- ## Connect The `connect` object sits inside the marketplace manifest and carries the following top-level fields. | JSON field | Type | Required | Description | | ------------------- | ------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `enable` | boolean | Optional | Master switch for the connect capability. When omitted, the platform infers whether connect is active from the other fields. | | `url` | string | Optional | Base URL of your connector's REST API. Each route's `path` is appended to this value to form the full request URL. | | `security` | object | Conditional | Authentication configuration that tells the platform how to sign requests to your API. Required whenever your API needs credentials — that is, for every authentication type except No Auth. | | `routes` | array | Optional | Definitions of the REST APIs your connector exposes; each entry is one call against the base `url`. Maximum 100 routes. | | `incoming_webhooks` | array | Optional | Definitions of the webhooks your service uses to push events to the platform. | | `mcp` | object | Optional | Configuration for a Model Context Protocol server exposed by your connector. | ### Enabling connect Whether the connect capability is active depends on `enable` and on whether you've actually provided any connect data. In practice, the minimum you need is to set `enable: true` and provide at least a `url`. If you want to ship a manifest with the connector temporarily turned off, set `enable: false` — your other connect fields are preserved in the manifest but not activated. The manifest tool will also consider connect as **disabled** and all connect data is ignored if `enable` is omitted **and** the connect object is effectively empty — that is, `url` is blank, `security` is null, `routes` is empty, and `incoming_webhooks` is empty. --- ## Security The `security` block tells the platform how to authenticate every request the connector makes to your API. You pick one authentication **type**, then supply the matching credential and endpoint fields inside `oauth_config`. | JSON field | Type | Required | Description | | -------------- | ------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `type` | integer | Required | The authentication method, given as a numeric code (for example, `1` for API Key or `31` for OAuth2 Authorization Code). See [type values](#type-values) for the full list of supported values. | | `oauth_config` | object | Conditional | Holds the credential and endpoint fields for the selected `type`. Required for every type that needs credentials (all types except No Auth). Despite its name, this object is used for all authentication types, not only OAuth. See [oauth config fields](#oauth_config-fields). | > **Validation notes** > > - If connect is enabled and the `security` block is malformed for the chosen type, the import is rejected with an authentication validation error. > - **MCP overrides `security`.** > > When an `mcp` block is present, the MCP configuration takes precedence over the `security` block — regardless of whether an authentication type is set — and authentication is handled as part of the MCP configuration instead. ### Type values Each authentication type has a stable numeric code. The codes are not sequential; gaps are intentional (some values are reserved and are not part of the manifest import path). Use only the values listed here. | `type` | Name | Fields used in `oauth_config` | | ------ | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | `1` | API Key | `key`, `api_key_type` | | `5` | Basic Auth | The `username` and `password` are provided by the end user when they connect, not configured in the manifest. | | `6` | Bearer Token | The `token` is provided by the end user when they connect, not configured in the manifest. | | `7` | JWT Bearer | `algorithm`, `add_to`, `secret` | | `8` | No Auth | — (no credentials) | | `9` | AWS SigV4 | `aws_*` fields. See [field details](#aws-sigv4-fields). | | `31` | OAuth2 Authorization Code | `authorize_url`, `access_token_url`, `client_id`, `client_secret`, `scope`, `client_authentication`, `refresh_url`, `advanced_config` | | `33` | OAuth2 Password | `access_token_url`, `client_id`, `client_secret`, `username`, `password`, `scope`, `client_authentication`, `refresh_url`, `advanced_config` | | `34` | OAuth2 Client Credentials | `access_token_url`, `client_id`, `client_secret`, `scope`, `client_authentication`, `refresh_url`, `advanced_config`, `jwt_client_assertion` | | `36` | OAuth2 Authorization Code + PKCE | Same as `31`, plus `code_challenge_method` | > **Notes for OAuth types** > > - **Redirect URL is server-assigned.** For Authorization Code (31) and Authorization Code + PKCE (36), the OAuth redirect URL is assigned by the platform when your manifest is imported. **Do not** set it in the manifest; register the assigned value with your identity provider after import. > - **Token request delivery.** On import, the OAuth token request is always sent with parameters in the request body. Any `request_type` value you supply is informational only and does not change this behavior. > - **Client Credentials** — (client_id / client_secret are optional) For OAuth2 Client Credentials (34), you may set `client_id` and `client_secret` in the manifest. If you do, they apply to every customer using the app. If you leave them out, each end user is prompted to provide their own when they install and connect the app. ### oauth_config fields These are the credential and endpoint fields referenced by the `security` type. Include only the fields that apply to your chosen `type`. | JSON field | Type | Applies to | Description | | ----------------------- | ------ | --------------------------- | --------------------------------------------------------------------------------------- | | `key` | string | API Key | Name of the header or query parameter that carries the API key. | | `api_key_type` | string | API Key | Where the key is sent — `header` or `query`. | | `token` | string | Bearer Token | The bearer token value (write-only). | | `username` | string | Basic Auth, OAuth2 Password | Username credential. | | `password` | string | Basic Auth, OAuth2 Password | Password credential (write-only). | | `algorithm` | string | JWT Bearer | Signing algorithm for the JWT, e.g. `HS256`. | | `add_to` | string | JWT Bearer | Where the signed JWT is placed on the request, e.g. `header`. | | `secret` | string | JWT Bearer | Signing secret used to produce the JWT (write-only). | | `client_id` | string | OAuth2 | OAuth client ID. | | `client_secret` | string | OAuth2 | OAuth client secret (write-only). | | `authorize_url` | string | OAuth2 Code / Code + PKCE | Authorization endpoint the user is redirected to. | | `access_token_url` | string | OAuth2 | Token endpoint used to exchange for an access token. | | `refresh_url` | string | OAuth2 | Token refresh endpoint. | | `scope` | string | OAuth2 | Space-separated list of scopes to request. | | `client_authentication` | string | OAuth2 | How client credentials are sent to the token endpoint: `header` (HTTP Basic) or `body`. | | `code_challenge_method` | string | OAuth2 Code + PKCE | PKCE challenge method: `S256` (recommended) or `plain`. | | `request_type` | string | OAuth2 | Informational only; the platform always sends token-request parameters in the body. | > **Write-only fields** > > Write-only fields (`token`, `password`, `secret`, `client_secret`) are accepted on import but are never returned when a manifest is exported. Treat them as sensitive: supply them once, and expect them to be redacted in any read-back of the manifest. ### AWS SigV4 fields Use these fields when authenticating to an AWS-hosted API with Signature Version 4. The role and region can be provided here as defaults and overridden per connection when a user sets up the connector. | JSON field | Type | Description | | --------------- | ------- | ---------------------------------------------------------------------------------------------------------------- | | `aws_is_header` | boolean | `true` places the signature in the request header (default); `false` places it in a query parameter. | | `aws_iam_role` | string | IAM role ARN used for the STS AssumeRole call. Can be set per connection; use the manifest to provide a default. | | `aws_region` | string | AWS region. Can be set per connection; use the manifest to provide a default. | --- ## Routes Each entry in `routes` defines one **REST API** the connector can call — a single request against your connector's base `url`. Routes are what become usable inside the Zoom platform (for example, as steps in a workflow or as tools an agent can invoke). Define one route per meaningful operation your API exposes. > **Note** > > - You can set up to a **maximum of 100 routes.** > - Every non-blank `key` must be **unique** across the array. The `key` is the identifier used to reference the route elsewhere (including from incoming webhooks); it is important to keep it stable across manifest versions. | JSON field | Type | Required | Description | | -------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | Required | Human-readable name for this API, shown to users. | | `path` | string | Required | Path appended to the connector's base `url`, e.g. `/users/me`. | | `method` | string | Required | HTTP method — one of `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `OPTIONS`, `HEAD`, `TRACE`. | | `key` | string | Required | Stable, unique identifier for this route. | | `description` | string | Optional | Longer description of what this API does. | | `parameters` | array | Optional | The route's inputs — path segments, query arguments, or headers. See [parameters](#parameters) for the shape of each entry. | | `request_body` | object | Optional | A structured definition of the request payload for methods that send a body. See [Request_body](#request_body) for details. | | `response` | object | Optional | A definition of the response your API returns, used to map its output into downstream steps. See [response](#response) for details. | Parameters that reference another route's output (cross-route dependencies) are validated after all routes have been parsed, so the referenced route can appear anywhere in the array. ### Parameters A parameter describes a single input to the route — a path segment, a query argument, or a header. Define one entry per input your API accepts so the platform can prompt for and pass the right values. To describe the request body, use the `request_body` [object](#request_body), not a parameter. | JSON field | Type | Required | Description | | ------------------ | ------- | -------- | ----------------------------------------------------------------------------------------------------- | | `name` | string | Required | Parameter name as sent to your API. Maximum 50 characters. Must not be blank. | | `displayName` | string | Optional | Friendly label shown to users. Maximum 50 characters. Defaults to `name` when omitted. | | `description` | string | Optional | Explanation of the parameter. Maximum 250 characters. | | `in` | string | Required | Where the parameter is sent: `path`, `query`, or `header`. Defaults to `header` on import if omitted. | | `required` | boolean | Optional | Whether the parameter must be provided by the caller. | | `schema` | object | Required | Data type and shape of the value. See 4.4 for the schema structure. | | `active` | boolean | Optional | Whether the parameter is active. Defaults to `true`. | | `explode` | boolean | Optional | Controls how arrays and objects are serialized (OpenAPI-style explode). Defaults to `false`. | | `disableUrlEncode` | boolean | Optional | If `true`, the value is not URL-encoded. Defaults to `false`. | | `allowEmptyValue` | boolean | Optional | If `true`, an empty value is allowed. Defaults to `false`. | ### Request_body Describes the payload sent with the route, for methods such as `POST`, `PUT`, and `PATCH`. The request body is defined here as a single structured schema — it is not described through the `parameters` array. | JSON field | Type | Required | Description | | ---------------- | ------- | -------- | ------------------------------------------------------------------------------------------- | | `description` | string | Optional | Explanation of the body. Maximum 250 characters. | | `required` | boolean | Optional | Whether the body must be provided. | | `content` | string | Optional | Content type, e.g. `application/json`. Maximum 100 characters. | | `schema` | object | Optional | Shape of the body. See [schema](#schema) for the schema structure. | | `standardSchema` | object | Optional | A normalized version of the schema, used when the body maps to a standard object shape. | | `json` | string | Optional | Example body as a JSON string. | | `testJson` | string | Optional | Sample body used for test calls. When present, it is parsed and validated as a data schema. | ### Response Describes the response your API returns for the route. Defining a response schema lets the platform map your API's output into downstream steps. | JSON field | Type | Required | Description | | ---------------- | ------ | -------- | ------------------------------------------------------------------------------------ | | `description` | string | Optional | Explanation of the response. Maximum 250 characters. | | `content` | string | Optional | Content type, e.g. `application/json`. Maximum 100 characters. | | `schema` | object | Optional | Shape of the response body. See [schema](#schema) for the schema structure. | | `standardSchema` | object | Optional | A normalized version of the schema. | | `headers` | array | Optional | Response headers, each described with the same fields as a [parameter](#parameters). | | `json` | string | Optional | Example response as a JSON string. | ### Schema A recursive, JSON-Schema-like structure used to describe the shape of parameters, request bodies, and responses. Nest it to represent arrays and objects of any depth. | JSON field | Type | Description | | ------------- | ------ | -------------------------------------------------------------------------- | | `key` | string | Stable identifier for the field. | | `name` | string | Field name. | | `displayName` | string | Friendly label for the field. | | `type` | string | Data type: `string`, `integer`, `number`, `boolean`, `array`, or `object`. | | `value` | any | Default or current value. | | `testValue` | any | Value used for test calls. | | `items` | object | Schema for each element, used when `type` is `array`. | | `properties` | array | Child schema entries, used when `type` is `object`. | | `dependency` | object | Describes a dependency on another parameter's value. | | `enum` | array | The set of allowed values for the field. | **Setting up recursion:** For an `array`, describe the element type in `items`. For an `object`, list its fields in `properties`, where each entry is itself a schema and can contain further `items` or `properties`. Primitive types (`string`, `integer`, `number`, `boolean`) are leaf nodes. --- ## Incoming webhooks An incoming webhook lets your service **push** events to the Zoom platform rather than being polled. Each entry defines one webhook the connector registers. There are two kinds of webhooks: - **`RestHook`** — the platform subscribes and unsubscribes by calling routes you've defined (for example, "create subscription" / "delete subscription" endpoints on your API). Use this when your service supports dynamic subscription management. - **`Static`** — a fixed webhook with no subscribe/unsubscribe lifecycle. Use this when events are delivered to a fixed endpoint. > **Limits and uniqueness** > > - The number of incoming webhooks an app can define is capped by a per-app maximum (**default 100**). > - Every non-blank `key` must be **unique**. | JSON field | Type | Required | Enum / Values | Description | | ------------------- | ------ | ----------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `name` | string | Required | — | Webhook name. Must not be blank. | | `short_description` | string | Optional | — | Short description of the webhook. | | `key` | string | Required | — | Stable, unique identifier for the webhook. | | `type` | string | Required | `RestHook`, `Static` | Webhook kind. If unknown or absent, defaults to `RestHook`. | | `status` | string | Required | `INCOMPLETE`, `READY` | Readiness status. Any other value (or absent) is rejected. | | `state` | string | Required | `ON`, `OFF` | Operational state (case-insensitive). Any other value is rejected. | | `authentication` | object | Required | — | Signature verification configuration; must not be null. See 5.1 for its fields. | | `validation` | object | Optional | — | Handshake validation configuration for the initial endpoint challenge. See 5.2 for its fields. | | `rest_hook` | object | Conditional | — | Subscribe/unsubscribe route bindings. Required when `type` is `RestHook`; must be absent when `type` is `Static`. See [rest_hook](#rest_hook) for field information. | > **Signing secret** > > A webhook typically reaches `status: READY` only once its signing secret is set. (See `secret` in [authentication](#authenticatiion)). Until then it may remain `INCOMPLETE`. ### Authentication Configures how the platform verifies that an incoming request genuinely came from your service, by checking a signature you attach to each delivery. | JSON field | Type | Required | Enum / Values | Description | | ----------- | ------ | -------- | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ | | `key` | string | Required | — | Name of the header or field that carries the signature. Must not be blank. | | `secret` | string | Optional | — | Signing secret used to verify the signature (write-only — omitted on export). Required for the webhook to reach `READY`. | | `algorithm` | string | Optional | `N/A`, `EQUAL`, `NOT_BLANK`, `HMAC_SHA256` | Signature algorithm. Validated only when non-blank; an unlisted value is rejected. | | `encoding` | string | Optional | `N/A`, `BASE64` | Signature encoding. Validated only when non-blank; an unlisted value is rejected. | | `prefix` | string | Optional | — | Optional prefix on the signature value, e.g. `sha256=`. | ### Validation Configures the initial handshake some services perform to confirm a webhook endpoint before sending events (an echo/challenge exchange). | JSON field | Type | Required | Description | | -------------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------- | | `enabled` | boolean | Optional | Enables handshake validation. If this is `false` or absent but `request_key`/`response_key` are set, the configuration is rejected. | | `request_key` | string | Optional | Field read from the incoming validation request. | | `response_key` | string | Optional | Field echoed back in the response. | ### Rest_hook `rest_hook` binds the webhook's subscribe and unsubscribe steps to routes you've defined and applies to `RestHook` webhooks only. | JSON field | Type | Required | Description | | ----------------------- | ------ | ----------------------- | ------------------------------------------------------------------------------------------------------------ | | `subscribe.route_key` | string | Required (for RestHook) | `key` of the route called to create the subscription. Must reference an existing route defined in section 4. | | `unsubscribe.route_key` | string | Required (for RestHook) | `key` of the route called to remove the subscription. Must reference an existing route defined in section 4. | --- ## MCP If your connector exposes a [Model Context Protocol](https://modelcontextprotocol.io) server, declare it here. This lets the connector surface your MCP tools on the platform. | JSON field | Type | Required | Description | | ---------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `base_url` | string | Required | MCP server base URL. Must be a valid HTTPS URL that passes domain validation. Leading and trailing whitespace is trimmed automatically. | | `name` | string | Optional | Display name for the MCP server. | | `ext` | object | Required | Container for extended MCP configuration; include it in your manifest. None of the fields available to you are individually required. See the note in [EXT](#ext) for why the object itself is still required. | ### EXT | JSON field | Type | Required | Description | | ------------- | ------ | -------- | ------------------------------ | | `description` | string | Optional | Description of the MCP server. | **Why `ext` is required but none of its listed fields are:** The complete manifest defines additional `ext` fields that are required internally but are managed by the platform and are not exposed to external developers. Because of those internal fields, the `ext` object itself must be present — but none of the externally-available fields listed above are required. Set `description` only if you need it. **Implementation rules:** - **How the OAuth client ID is obtained** For an MCP connector, Zoom obtains the OAuth client ID programmatically — it registers with your authorization server automatically, using either Dynamic Client Registration (DCR) or a Client ID Metadata Document (CIMD). The Zoom MCP client supports both. Because registration is handled programmatically, do not set a static `client_id` in `security.oauth_config`; if you supply one, it is rejected on import. - If `base_url` fails validation, or the server is unsupported, or another server-side error occurs, the import is rejected with a corresponding validation error. --- ## Constraints & limits | Area | Constraint | | -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Routes | ≤ 100 entries; each non-blank `key` must be unique; `method` must be one of the allowed HTTP methods. | | Parameter `name` / `displayName` | ≤ 50 characters. | | `description` (parameters / body / response) | ≤ 250 characters. | | `content` (body / response) | ≤ 100 characters. | | Parameter `in` | Defaults to `header` on import if omitted. | | Security | A malformed `security` block is rejected (unless an `mcp` block is present, which overrides `security`); OAuth token requests are always sent in the body; the redirect URL is server-assigned for Authorization Code and Authorization Code + PKCE. | | Incoming webhooks | ≤ per-app maximum (**default 100**); each non-blank `key` must be unique; `authentication` and its `key` are required; `status` ∈ {`INCOMPLETE`, `READY`}; `state` ∈ {`ON`, `OFF`}; `type` ∈ {`RestHook`, `Static`}; `algorithm` ∈ {`N/A`, `EQUAL`, `NOT_BLANK`, `HMAC_SHA256`}; `encoding` ∈ {`N/A`, `BASE64`}; each `rest_hook` route key must reference an existing route; the signing secret is write-only. | | MCP | `base_url` must be a valid HTTPS URL; the `ext` object must be present (though none of its externally-available fields are required); the OAuth client ID is obtained programmatically via DCR or CIMD, so a static `client_id` must not be set (it is rejected on import). |