Skip to content

Dynamic URL Path Segments

Most REST APIs put resource identifiers in the URL path (/users/{id}/posts, /ideas/{id}/endorsements). To call these from a widget, declare each variable segment as a path parameter and reference it in the connector URL with {{ pathParams.X }}. Callers supply the value at run time; the platform validates it as URL-safe and substitutes it into the URL.

This avoids the alternative of either creating one connector per resource ID, or hacking the value into the upstream API's query string when the upstream expects it in the path.

Quick example

A connector that fetches the endorsements for a single idea, where idea_id is supplied by the widget per call.

In the connector configuration, declare the path parameter under the Path Parameters section:

FieldValue
Keyidea_id

Set the connector URL to:

https://api.example.com/ideas/{{ pathParams.idea_id }}/endorsements

Then call it from the widget:

javascript
(async () => {
  const sdk = new window.WidgetServiceSDK();
  const data = await sdk.connectors.execute({
    permalink: "idea-endorsements",
    method: "GET",
    pathParams: { idea_id: 42 }
  });
  console.log(data);
})();

The outbound request becomes:

GET https://api.example.com/ideas/42/endorsements

Validation rule

Every path-parameter value is validated against one universal rule:

  • Allowed characters: letters, digits, and . _ ~ - (the RFC 3986 unreserved set)
  • Length: 1–200 characters
  • Rejected: empty values, whitespace, /, ?, #, %, spaces, control characters, and path-traversal segments (., .., anything containing ..)

Accepts: 42, user-42, USER_42, my.handle, a~b, RFC 4122 UUIDs in any case. Rejects: empty, has space, with/slash, with?q, .., %20, with#hash.

Path parameters and query parameters are configured in separate sections of the connector — path-parameter values are substituted into {{ pathParams.X }} template references in the URL path, while query-parameter entries are appended to the query string.

Authorization

The platform validates that path-parameter values are URL-safe, but it does not authorize the caller's access to the resource they identify. A widget supplying pathParams: { user_id: 42 } has 42 substituted into the URL whether or not the authenticated user is user 42 — the same way a query parameter or overridable header would.

Two patterns keep this safe:

  • Upstream enforces it. The destination API rejects requests the caller is not entitled to. Typical for production REST APIs with per-resource ACLs.
  • Pin the value server-side. When the path parameter must equal the authenticated user (or another value the browser cannot change), drop the path parameter and put a server-side template variable like {{ user.id }} directly in the connector URL. See Passing User Context.

Validation and errors

Values are validated server-side before any outbound call is made — the upstream API never sees a malformed input. The connector execution endpoint returns a 400 with a structured error body on validation failure:

codeWhen it fireserrors shape
INVALID_PATH_PARAMETERSAt least one caller-supplied value fails URL-safe validation (wrong characters, too long, path-traversal segment, etc.){ code, params: string[] } — flat list of failing keys
MISSING_PATH_PARAMETERSThe URL template references {{ pathParams.X }} but no value was supplied for X (one or more keys){ code, params: string[] } — flat list of missing keys
CONNECTOR_MISCONFIGUREDThe URL references a path parameter that has no declared row in path_parameters{ code, detail }

Missing wins over invalid: if any required key is missing, only MISSING_PATH_PARAMETERS is returned; value validation runs only when all required keys are supplied. The substituted value is quote(value, safe="")-encoded before reaching the upstream URL.

Composite connectors

Path parameters are not supported on composite connectors. The SDK's sdk.connectors.composite.execute throws ConnectorBoundaryError synchronously if pathParams is supplied — no request is sent. If you need per-call path values in a composite flow, compose simple connectors from inside the composite's step URLs using the step result variables.

SDK reference

The pathParams field on sdk.connectors.execute accepts Record<string, string | number>. The SDK serializes the values into an X-Path-Params HTTP header in urlencoded form (same wire shape as a query string) and the server reads them from there. You don't need to handle the encoding — the SDK does it.

javascript
await sdk.connectors.execute({
  permalink: "user-posts",
  method: "GET",
  pathParams: { user_id: 42, post_slug: "hello-world" }
});

// Outbound:
//   GET /connectors/user-posts/execute
//   X-Path-Params: user_id=42&post_slug=hello-world

Boundary validation runs synchronously before any network call:

TriggerSDK behaviour
Empty / whitespace-only key ({ "": "x" })Throws ConnectorBoundaryError
Value whose type is not string or number (e.g. null, an object, a boolean)Throws ConnectorBoundaryError
Serialized payload over 4096 charactersThrows ConnectorBoundaryError
Passed to composite.execute with at least one keyThrows ConnectorBoundaryError
Omitted or {}No header sent — request goes out unchanged

ConnectorBoundaryError is distinct from ConnectorExecuteError (which normalises server-side failures from the response body). For path-parameter validation failures the server returns the envelope shape { success: false, errors: { code, params, detail }, request_id }; ConnectorExecuteError exposes those as optional code, params, and detail fields. Branch on err.code to handle each error:

javascript
import { ConnectorBoundaryError, ConnectorExecuteError } from "@gainsight-hub/connectors-sdk";

try {
  await sdk.connectors.execute({ permalink: "...", method: "GET", pathParams: { id } });
} catch (err) {
  if (err instanceof ConnectorBoundaryError) {
    // Client-side rejection — fix the caller
  } else if (err instanceof ConnectorExecuteError) {
    switch (err.code) {
      case "MISSING_PATH_PARAMETERS":
      case "INVALID_PATH_PARAMETERS":
        // err.params: string[] — the failing keys
        break;
      case "CONNECTOR_MISCONFIGURED":
        // err.detail: string — operator-facing detail
        break;
      default:
        // Legacy shape (or an unrecognised envelope code) — err.failureScope / err.reason / err.requestId / err.status
    }
  }
}

Next steps

Gainsight CC Developer Portal