Appearance
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:
| Field | Value |
|---|---|
| Key | idea_id |
Set the connector URL to:
https://api.example.com/ideas/{{ pathParams.idea_id }}/endorsementsThen 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/endorsementsValidation 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:
code | When it fires | errors shape |
|---|---|---|
INVALID_PATH_PARAMETERS | At 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_PARAMETERS | The 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_MISCONFIGURED | The 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-worldBoundary validation runs synchronously before any network call:
| Trigger | SDK 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 characters | Throws ConnectorBoundaryError |
Passed to composite.execute with at least one key | Throws 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
- Headers & Query Parameters — for values that go in the query string, not the URL path
- Template Variables — full reference for Jinja2 expressions in connector URLs and templates
- Calling from Widget Code — full SDK usage for widgets
- Testing & Debugging — verify path parameters substitute correctly

