Skip to content

Composite Connectors

Chain multiple API calls into a single execution when your widget needs data that requires more than one request — for example, authenticating with one service, then fetching data from another. This guide covers how to define, execute, and debug composite connectors.

Prerequisites

How execution flows

Steps run sequentially — step 2 waits for step 1 to complete. If any step fails with an HTTP 4xx/5xx or network error, execution stops immediately and the final response is an error. The response returned to the widget is always the last step's response.

Define a composite connector

To create a composite connector, add an entry under the composite_connectors array in your connectors_registry.json:

json
{
  "connectors": [...],
  "composite_connectors": [
    {
      "name": "Auth and Fetch User",
      "permalink": "auth-and-fetch-user",
      "steps": [
        {
          "name": "auth",
          "url": "https://auth.example.com/oauth/token",
          "method": "POST",
          "headers": [
            {"key": "Content-Type", "value": "application/json"}
          ],
          "authentication": {
            "type": "oauth_client_credentials",
            "config": {
              "client_id": "{{ get_secret('oauth_client_id') }}",
              "client_secret": "{{ get_secret('oauth_client_secret') }}",
              "token_url": "https://auth.example.com/oauth/token"
            }
          }
        },
        {
          "name": "fetch-user",
          "url": "https://api.example.com/users/me",
          "method": "GET",
          "headers": [
            {
              "key": "Authorization",
              "value": "Bearer {{ steps.auth.body | from_json | attr('access_token') }}"
            }
          ]
        }
      ]
    }
  ]
}

Push the file to your watched branch. The platform syncs the composite connector automatically — the same way it syncs regular connectors.

Composite connectors have no admin UI

You can only create and edit composite connectors through your repository registry. There is no visual editor for them.

For the full list of step fields and variables, see Composite Connector Reference.

Pass data between steps

To use a value from a previous step, reference it with steps.<name>.body in any Jinja2 template field (URL, headers, request body). Parse JSON responses with from_json, then pick fields with attr():

jinja2
Bearer {{ steps.auth.body | from_json | attr('access_token') }}

If the previous step's response is large and you only need one field, transform it once at the source by setting response_body on that step:

json
{
  "name": "auth",
  "url": "https://auth.example.com/oauth/token",
  "method": "POST",
  "response_body": "{{ response.body | from_json | attr('access_token') }}"
}

After this, steps.auth.body holds just the token string, and later steps can reference it directly as Bearer {{ steps.auth.body }}.

Step names use slug format

Step names use slug format: lowercase letters, digits, and hyphens (for example, auth, fetch-user). For single-word names use dot notation: steps.auth.body. For hyphenated names use bracket notation: steps['fetch-user'].body.

Use incoming request data in steps

To drive step behavior from the client's request — for example, a user ID sent in the request body — reference the request object in any step template:

jinja2
{# In a step URL or request_body template #}
{{ request.body_text | from_json | attr('userId') }}

The request object exposes the client's body, headers, and query parameters. See Composite Connector Reference for the full list.

Different from regular connectors

Regular connectors use body_text and body_raw directly in payload templates. Composite connectors use request.body_text and request.body_raw — the request. prefix distinguishes client data from step result data.

Execute a composite connector

To call a composite connector from widget code, use sdk.connectors.composite.execute():

html
<script>
(async () => {
  const sdk = new window.WidgetServiceSDK();
  try {
    const data = await sdk.connectors.composite.execute({
      permalink: "auth-and-fetch-user"
    });
    console.log("Result:", data);
  } catch (error) {
    console.error("Connector request failed:", error);
  }
})();
</script>

The HTTP method is always POST — it is not a configurable parameter. The SDK owns this detail so you do not need to specify it.

Path parameters are not supported on composite connectors

pathParams is a simple-connector concept only. Passing pathParams to sdk.connectors.composite.execute() throws ConnectorBoundaryError synchronously — no request is sent. If you need per-call path values inside a composite flow, embed them in the step URLs using template variables from previous steps' results. See Dynamic URL Path Segments for the simple-connector pattern.

To pass a request body, include the payload option as a plain object. The SDK handles serialisation. Use queryParams to append URL query parameters — these are available in step templates as request.query_parameters.<key>:

html
<script>
(async () => {
  const sdk = new window.WidgetServiceSDK();
  try {
    const data = await sdk.connectors.composite.execute({
      permalink: "auth-and-fetch-user",
      payload: { userId: "usr_123" },
      queryParams: { format: "json" }
    });
    console.log("Result:", data);
  } catch (error) {
    console.error("Connector request failed:", error);
  }
})();
</script>

Debug failing steps

When a step fails, the platform returns a single error response identifying which step failed:

  • HTTP 4xx/5xx from a step — returns 502 with the failed step's name and index
  • Network error on a step — returns 502 with step identification
  • Template rendering error — returns 422 with the affected step and template error

No data from previous successful steps is included in the error response.

Example errors.scope value in the JSON error response: Composite step 'fetch-user' (index 1): Downstream (HTTP error)

To see per-step timing, inspect the response headers:

  • Server-Timing — includes a step.<name>;dur=<ms> entry per step, plus total
  • X-Connector-Timing — JSON with per-step breakdown
Server-Timing: step.auth;dur=120.5;desc="Step: auth", step.fetch-user;dur=85.3;desc="Step: fetch-user", total;dur=210.1;desc="Total"

Next Steps

Gainsight CC Developer Portal