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

# SDK / API Reference

Below are all the public functions exposed on the Paragon SDK (which can be accessed as the named `paragon` export from `@useparagon/connect`) and public endpoints of the Paragon REST API.

**For [on-premise](/on-premise/hosting-paragon-on-premise) users:**

If you are using an on-premise instance of Paragon, you can call the `.configureGlobal` function to point the SDK to use the base hostname of your Paragon instance.

```js theme={null}
import { paragon } from "@useparagon/connect";

// If your login URL is https://dashboard.mycompany.paragon.so:
paragon.configureGlobal({
  host: "mycompany.paragon.so",
});
```

### <span id="authenticate">.authenticate(projectId: string, userToken: string)</span>

`.authenticate` should be called at the beginning of your application's lifecycle in all cases. This is to make sure that the `userToken` is always as fresh as possible, with respect to your user's existing session on your own site.

```js JavaScript SDK theme={null}
await paragon.authenticate(
  // You can find your project ID in the Overview tab of any Integration
  "38b1f170-0c43-4eae-9a04-ab85325d99f7",

  // See Setup for how to encode your user token
  "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.ey..."
);
```

Once `.authenticate` has been called, you can access the user's integration state with `.getUser()`. `.authenticate()` only needs to be called when using the Paragon SDK - when making requests to the Paragon REST API, you should instead provide the Paragon User Token in the Authorization header.

### <span id="connect">.connect(integrationType: string, installOptions?: InstallOptions)</span>

Call `.connect` to launch your Connect Portal for a specific integration provider. You can find the `integrationType` identifier you need in the Overview page for the integration.

```js JavaScript SDK theme={null}
paragon.connect("salesforce");
```

This function must be called after the Paragon SDK has completed authentication. You can `await` the Promise returned by [`.authenticate`](#authenticate) to show a loading state before users are able to access the Connect Portal.

You *must* have an integration configured of this `integrationType` in your Paragon project for the Connect Portal to appear. Otherwise, this function does nothing.

If your integration uses a [Field Mapping](/connect-portal/field-mapping) User Setting, pass the mapping configuration through `installOptions`. For examples, see [Passing dynamic fields through the SDK](/connect-portal/field-mapping#passing-dynamic-fields-through-the-sdk).

<Accordion title="Optional installOptions">
  <ParamField body="onSuccess" type="function">
    Callback invoked when an integration is successfully enabled.
  </ParamField>

  <ParamField body="onError" type="function">
    Callback if an unexpected error occurs.
  </ParamField>

  <ParamField body="accountType" type="enum">
    For integrations that support multiple account types, you can optionally designate a specific `accountType` to skip the account selection dialog.

    Example values: `default`, `sandbox`

    ```js Example of using accountType theme={null}
    paragon.connect("salesforce", {
      // Only allow production-type Salesforce accounts to connect
      accountType: "default",
    });
    ```
  </ParamField>

  <ParamField body="mapObjectFields" type="object">
    For [Field Mapping](/connect-portal/field-mapping) inputs that use Dynamic Application Fields. Keys must match the Application Object Name from the dashboard; values describe application fields and/or loaders for integration object types and fields. See [Passing dynamic fields through the SDK](/connect-portal/field-mapping#passing-dynamic-fields-through-the-sdk).
  </ParamField>

  <ParamField body="externalId" type="string">
    Pass this option to associate a new credential with an identifier from your own system. The `externalId` will be available on the credential object returned by [`getUser()`](/apis/api-reference#getuser).

    This option cannot be used with `selectedCredentialId`, which is used to replace or manage existing connected accounts. Existing credentials currently cannot be updated with an external ID.
  </ParamField>

  <ParamField body="selectedCredentialId" type="string">
    Used for [Multi-Account Authorization](/apis/api-reference/multi-account-authorization). Pass this option to open the Connect Portal for an existing credential ID and update/manage settings (headful) or to start an install flow to replace an existing credential ID with a new account (with the [Headless Connect Portal](/connect-portal/headless-connect-portal)).
  </ParamField>

  <ParamField body="selectedConfigurationId" type="string">
    Used for [Multi-Configuration](/apis/api-reference/multi-configuration). Pass this option to open the Connect Portal for a specific configuration (unique set of User Settings and Workflow Enablements for a connected credential).
  </ParamField>
</Accordion>

You can also connect multiple accounts for the same integration.

<Card title="Multi Account Authorization" href="/apis/api-reference/multi-account-authorization" horizontal arrow />

### .disableWorkflow(workflowId: string) -> Promise

Call `.disableWorkflow` to turn off a workflow for a user by ID.

<CodeGroup>
  ```javascript JavaScript SDK theme={null}
  paragon.disableWorkflow("<Workflow ID>");
  ```

  REST API

  ```http REST API theme={null}
  DELETE https://api.useparagon.com/projects/<Project ID>/sdk/workflows/<Workflow ID>

  Authorization: Bearer <Paragon User Token>
  ```
</CodeGroup>

### .enableWorkflow(workflowId: string) -> Promise

Call `.enableWorkflow` to turn on a workflow for a user by ID.

<CodeGroup>
  ```javascript JavaScript SDK theme={null}
  paragon.enableWorkflow("<Workflow ID>");
  ```

  REST API

  ```http REST API theme={null}
  POST https://api.useparagon.com/projects/<Project ID>/sdk/workflows/<Workflow ID>

  Authorization: Bearer <Paragon User Token>
  ```
</CodeGroup>

### <span id="getcustomwebhookusermanualurl">.getCustomWebhookUserManualUrl(workflowId: string, credentialId?: string)</span>

If you are using [Custom Webhooks](/resources/custom-webhooks) with a User-Level URL and [Manual Setup](/resources/custom-webhooks#option-2%3A-manual-setup), you can use `getCustomWebhookUserManualUrl` to construct the user-specific URL that must be registered by your customer in the integration to complete webhook setup.

There is no API endpoint available for this method. However, you can construct the user-specific URL without the JavaScript SDK as described in the [Custom Webhooks docs](/resources/custom-webhooks#user-specific-webhook-target-urls).

<CodeGroup>
  ```javascript JavaScript SDK theme={null}
  // Present this value to your user to register this webhook in their account manually
  const webhookUrl = paragon.getCustomWebhookUserManualUrl("<Workflow ID>");
  ```
</CodeGroup>

**Arguments:**

<ParamField path="workflowId" type="string" required>
  The ID of a Workflow that utilizes this Custom Webhook. If the same Custom Webhook is used in multiple Workflows, any one of these workflows can be used as `workflowId`.
</ParamField>

<ParamField path="credentialId" type="string">
  If you are using [Multi-Account Authorization](/apis/api-reference/multi-account-authorization) and there may be more than one account connected for a given integration, pass the `credentialId` to ensure that received events are routed to the correct account.
</ParamField>

### <span id="getdatasourceoptions">.getDataSourceOptions(integrationType: string, sourceType: string)</span>

Call `.getDataSourceOptions` to get configuration details for **compound** data sources used for dynamic [User Settings types](/connect-portal/headless-connect-portal#exposing-user-settings) in the Headless Connect Portal.

Compound data sources, for Field Mapping and Combo Dropdown inputs, have multiple data sources within them (Field Mappings have both Object Types and Field Names as sources).

To load options for a data source, see [`getFieldOptions`](#getfieldoptions).

<Info>
  **SDK 2.3.0+:** Consider using [`getSourcesForInput`](#getsourcesforinput) instead, which provides a simpler way to get all data sources needed for any input type in a single call.
</Info>

**Arguments:**

<ParamField path="integrationType" type="string" required>
  An integration type string, like `salesforce`.
</ParamField>

<ParamField path="sourceType" type="string" required>
  A source type string, which can be found in the `sourceType` property of a
  User Setting object from [`getIntegrationConfig`](#getintegrationconfig) or
  from `stage.options` of `PostOptionsStage`.
</ParamField>

**Examples:**

<CodeGroup>
  ```js JavaScript SDK (Field Mapping) expandable theme={null}
  await paragon.getDataSourceOptions(
    "salesforce",
    "customObjectMapping",
  );

  // Returns:
  {
    "id": "customObjectMapping",
    "type": "FIELD_MAPPER_DATA_SOURCE",
    "title": "Field Mapping",
    "subtitle": "Allows users to define a field mapping",
    "recordSource": {
      "type": "DYNAMIC_DATA_SOURCE",
      "title": "Record Type",
      "cacheKey": "recordTypes",
    },
    "fieldSource": {
      "type": "DYNAMIC_DATA_SOURCE",
      "title": "Field",
      "cacheKey": "cachedFields",
    },
  }
  ```

  ```js JavaScript SDK (Combo Dropdown) expandable theme={null}
  await paragon.getDataSourceOptions(
    "jira",
    "projectIssueStatusTypeCombo",
  );

  // Returns:
  {
    "id": "projectIssueStatusTypeCombo",
    "type": "COMBO_INPUT_DATA_SOURCE",
    "title": "Issue Status",
    "subtitle": "The stage the issue is at, e.g. To Do or Done",
    "mainInputSource": {
      "type": "DYNAMIC_DATA_SOURCE",
      "cacheKey": "projects",
      "title": "Project",
      "subtitle": "Jira project that issues can be created in",
    },
    "dependentInputSource": {
      "type": "DYNAMIC_DATA_SOURCE",
      "cacheKey": "issueIssueStatusByProject",
      "title": "Issue Status",
      "subtitle": "The stage the issue is at, e.g. To Do or Done",
    }
  }
  ```
</CodeGroup>

### <span id="getsourcesforinput">.getSourcesForInput(integrationType: string, input: Input)</span>

Call `.getSourcesForInput` to get all the data sources needed to render a dynamic input (e.g. a picklist loaded from integration data from the user's connected account).

The returned data sources can be passed directly to [`getFieldOptions`](#getfieldoptions) using the `source` parameter to load options for your input, with pagination and search.

**Arguments:**

<ParamField path="integrationType" type="string" required>
  An integration type string, like `salesforce`.
</ParamField>

<ParamField path="input" type="Input" required>
  The input object from `availableUserSettings`, `availableWorkflows[n].inputs`, or `stage.options` of an install flow stage.
</ParamField>

**Returns:**

Returns `null` for inputs that don't require a data source (e.g. text inputs). Otherwise, returns one of the following based on the [Input Type](/connect-portal/input-types-reference) of the input:

<Tabs>
  <Tab title="SingleSource">
    Returned for [`DynamicEnum`](/connect-portal/input-types-reference) and [`CustomDropdown`](/connect-portal/input-types-reference) input types.

    <ParamField path="kind" type="const" required>
      `"single"` for SingleSource.
    </ParamField>

    <ParamField path="source" type="DynamicDataSource | StaticEnumDataSource" required>
      The data source for the input. Pass this to [`getFieldOptions`](#getfieldoptions) using the `source` parameter to load options.
    </ParamField>

    **Example:**

    ```js DynamicEnum input expandable theme={null}
    const config = paragon.getIntegrationConfig("slack");
    const input = config.availableUserSettings[0];
    // { id: "...", type: "DYNAMIC_ENUM", title: "Channel", sourceType: "channels" }

    const sources = paragon.getSourcesForInput("slack", input);
    // { kind: "single", source: { type: "DYNAMIC_DATA_SOURCE", cacheKey: "channels", ... } }

    if (sources?.kind === "single") {
      const options = await paragon.getFieldOptions({
        integration: "slack",
        source: sources.source,
      });
      // { data: [{ label: "#general", value: "general" }, ...], nextPageCursor: "..." }
    }
    ```
  </Tab>

  <Tab title="FieldMapperSources">
    Returned for [`FieldMapper`](/connect-portal/input-types-reference) input types.

    <ParamField path="kind" type="const" required>
      `"fieldMapper"` for FieldMapperSources.
    </ParamField>

    <ParamField path="recordSource" type="DynamicDataSource" required>
      The data source for loading record types. Pass to [`getFieldOptions`](#getfieldoptions) to load record type options.
    </ParamField>

    <ParamField path="fieldSource" type="DynamicDataSource" required>
      The data source for loading fields. Pass to [`getFieldOptions`](#getfieldoptions) with `parameters` for the selected record type to load available fields.
    </ParamField>

    <ParamField path="dependentInputSource" type="DynamicDataSource">
      An optional data source for a dependent input within the field mapping.
    </ParamField>

    <ParamField path="mapObjectFieldOptions" type="DynamicMappingOptions | DynamicMappingField[]">
      Pre-configured field mapping options, if provided via [`setDataSources`](#setdatasources).
    </ParamField>

    **Example:**

    ```js FieldMapper input expandable theme={null}
    const config = paragon.getIntegrationConfig("salesforce");
    const input = config.availableUserSettings[0];
    // { id: "...", type: "FIELD_MAPPER", title: "Map fields", sourceType: "customObjectMapping" }

    const sources = paragon.getSourcesForInput("salesforce", input);
    // { kind: "fieldMapper", recordSource: {...}, fieldSource: {...} }

    if (sources?.kind === "fieldMapper") {
      // Load record types
      const recordTypes = await paragon.getFieldOptions({
        integration: "salesforce",
        source: sources.recordSource,
      });

      // Load fields for a selected record type
      const fields = await paragon.getFieldOptions({
        integration: "salesforce",
        source: sources.fieldSource,
        parameters: [{
          key: sources.recordSource.cacheKey,
          source: { type: "VALUE", value: "Task" },
        }],
      });
    }
    ```
  </Tab>

  <Tab title="ComboSources">
    Returned for [`ComboInput`](/connect-portal/input-types-reference) input types (e.g. Combo Dropdown).

    <ParamField path="kind" type="const" required>
      `"combo"` for ComboSources.
    </ParamField>

    <ParamField path="mainInputSource" type="DynamicDataSource" required>
      The data source for the primary input. Pass to [`getFieldOptions`](#getfieldoptions) to load main options.
    </ParamField>

    <ParamField path="dependentInputSource" type="DynamicDataSource" required>
      The data source for the dependent input. Pass to [`getFieldOptions`](#getfieldoptions) with `parameters` for the user's main selection.
    </ParamField>

    **Example:**

    ```js ComboInput expandable theme={null}
    const config = paragon.getIntegrationConfig("jira");
    const input = config.availableUserSettings[0];
    // { id: "...", type: "COMBO_INPUT", sourceType: "projectIssueStatusTypeCombo" }

    const sources = paragon.getSourcesForInput("jira", input);
    // { kind: "combo", mainInputSource: {...}, dependentInputSource: {...} }

    if (sources?.kind === "combo") {
      // Load main options (e.g. Projects)
      const projects = await paragon.getFieldOptions({
        integration: "jira",
        source: sources.mainInputSource,
      });

      // Load dependent options (e.g. Issue Statuses for a selected Project)
      const statuses = await paragon.getFieldOptions({
        integration: "jira",
        source: sources.dependentInputSource,
        parameters: [{
          key: sources.mainInputSource.cacheKey,
          source: { type: "VALUE", value: "PROJECT-1" },
        }],
      });
    }
    ```
  </Tab>

  <Tab title="DefaultFieldValueSources">
    Returned for [`DynamicComboInput`](/connect-portal/input-types-reference) input types.

    <ParamField path="kind" type="const" required>
      `"defaultFieldValue"` for DefaultFieldValueSources.
    </ParamField>

    <ParamField path="mainInputSource" type="DynamicDataSource" required>
      The data source for the primary input. Pass to [`getFieldOptions`](#getfieldoptions) to load main options.
    </ParamField>

    <ParamField path="dependentInputSource" type="DynamicDataSource" required>
      The data source for the dependent input. Pass to [`getFieldOptions`](#getfieldoptions) with `parameters` for the user's main selection.
    </ParamField>

    <ParamField path="variableInputSource" type="DynamicDataSource">
      An optional data source for a variable input.
    </ParamField>

    **Example:**

    ```js DynamicComboInput expandable theme={null}
    const config = paragon.getIntegrationConfig("salesforce");
    const input = config.availableUserSettings[0];
    // { id: "...", type: "DYNAMIC_COMBO_INPUT", sourceType: "dynamicComboAction" }

    const sources = paragon.getSourcesForInput("salesforce", input);
    // { kind: "defaultFieldValue", mainInputSource: {...}, dependentInputSource: {...}, variableInputSource: {...} }

    if (sources?.kind === "defaultFieldValue") {
      const mainOptions = await paragon.getFieldOptions({
        integration: "salesforce",
        source: sources.mainInputSource,
      });

      const dependentOptions = await paragon.getFieldOptions({
        integration: "salesforce",
        source: sources.dependentInputSource,
        parameters: [{
          key: sources.mainInputSource.cacheKey,
          source: { type: "VALUE", value: mainOptions.data[0].value },
        }],
      });
    }
    ```
  </Tab>
</Tabs>

### <span id="getfieldoptions">.getFieldOptions(fieldOptions: FieldOptions)</span>

Load options from an integration data source for dynamic [User Settings types](/connect-portal/headless-connect-portal#exposing-user-settings) in the Headless Connect Portal, using the Connected User's account.

**`getFieldOptions()` can only be called for data sources with type `DYNAMIC_DATA_SOURCE`** (for dynamic enum input types).

* Compound data sources like `FIELD_MAPPER_DATA_SOURCE` or `COMBO_INPUT_DATA_SOURCE` are composed of `DYNAMIC_DATA_SOURCE`-type sources.

* When rendering Field Mapping or Combo Dropdown inputs, first identify each data source with [`getSourcesForInput`](#getsourcesforinput) (or [`getDataSourceOptions`](#getdatasourceoptions)), and use the returned data source configuration to call `getFieldOptions`. [See a full example.](/connect-portal/headless-connect-portal#exposing-user-settings)

This function supports search and pagination; see the parameters for `fieldOptions` below to learn more.

**Arguments:**

<ParamField path="fieldOptions" type="FieldOptions" required>
  <Accordion title="Show child properties">
    <ParamField path="integration" type="string" required>
      An integration type string, like `salesforce`.
    </ParamField>

    <ParamField path="action" type="string">
      A source type string, which can be found in the `sourceType` property of a User Setting object from [`getIntegrationConfig`](#getintegrationconfig) or from `stage.options` of `PostOptionsStage`.

      Either `action` or `source` must be provided.
    </ParamField>

    <ParamField path="source" type="DynamicDataSource">
      A `DynamicDataSource` object, as returned by [`getSourcesForInput`](#getsourcesforinput). When provided, the `cacheKey` of the source is used to identify the data source to load options from.

      Either `action` or `source` must be provided.
    </ParamField>

    <ParamField path="search" type="string">
      A user-provided search query for an option. When provided, the data source will return options that match this query.
    </ParamField>

    <ParamField path="cursor" type="string">
      A page cursor to use to load subsequent pages of results. The response of `getFieldOptions` will provide `nextPageCursor` to use or `null` if there are no more results.
    </ParamField>

    <ParamField path="parameters" type="Parameter[]">
      When loading options for a compound data source (e.g. `fieldSource` of a Field Mapping input or `dependentInputSource` of a Combo Dropdown input), pass parameters with the user's selection from the first input (e.g. the Record Type for Field Mapping).

      <Accordion title="Show child properties">
        <ParamField path="key" type="string">
          The `cacheKey` property of the primary/first input in the compound data sources (e.g. `recordSource` of a Field Mapping input or `mainInputSource` of a Combo Dropdown input).
        </ParamField>

        <ParamField path="source" type="string">
          <Accordion title="Show child properties">
            <ParamField path="type" type="const" required>
              Set this to `"VALUE"`.
            </ParamField>

            <ParamField path="value" type="string" required>
              Set this to the `value` property of the user's selection.
            </ParamField>
          </Accordion>
        </ParamField>
      </Accordion>
    </ParamField>

    <ParamField path="selectedCredentialId" type="string">
      If you are using [Multi-Account Authorization](/apis/api-reference/multi-account-authorization) and there may be more than one account connected for a given integration, pass `selectedCredentialId` to load options for the current account.
    </ParamField>
  </Accordion>
</ParamField>

**Returns:**

<ParamField path="data" type="Option[] | Section[]" required>
  <Accordion title="Show child properties">
    `data` will be an Array of either `Option` or `Section` objects, which should be handled by your Dropdown input.

    <Tabs>
      <Tab title="Option">
        <ParamField path="label" type="string" required>
          The human-readable display name to use for this option when displaying
          it to your user.
        </ParamField>

        <ParamField path="value" type="string" required>
          The unique value of this option to save with `setPreOptions`,
          `setPostOptions`, `updateIntegrationUserSettings`, or
          `updateWorkflowUserSettings`. This value can also be passed as
          `parameters[].source.value` for dependent inputs of compound data
          sources.
        </ParamField>
      </Tab>

      <Tab title="Section">
        <ParamField path="title" type="string" required>
          The title of this section of options.
        </ParamField>

        <ParamField path="items" type="Option[]" required>
          The list of options that should be contained in this section.
        </ParamField>
      </Tab>
    </Tabs>
  </Accordion>
</ParamField>

<ParamField path="nestedData" type="object[]">
  This section is an empty array for all input types except for **Default value mapping**, which is only supported by Jira: Issue Field Values.
</ParamField>

<ParamField path="nextPageCursor" type="string | null">
  The cursor value to pass as `cursor` for the next page of results.
</ParamField>

**Examples:**

<CodeGroup>
  ```js JavaScript SDK expandable theme={null}
  await paragon.getFieldOptions({
    integration: "slack",
    action: "channels",
    search: "general",
  });

  // Returns:
  {
    "data": [
      {
        "label": "#general",
        "value": "general"
      },
    ],
    "nestedData": [],
    "nextPageCursor": "dGVhbTpDMDUxWjlNSzk4Vw=="
  }
  ```

  ```js JavaScript SDK (Field Mapping) expandable theme={null}
  // Load Record Types:
  await paragon.getFieldOptions({
    integration: "salesforce",
    action: "recordTypes", // from `recordSource.cacheKey` of data source options
  });

  // Load Fields: 
  await paragon.getFieldOptions({
    integration: "salesforce",
    action: "cachedFields", // from `fieldSource.cacheKey` of data source options
    parameters: [{
      "key": "recordTypes",
      "source": {
        "type": "VALUE",
        "value": "Task" // The `value` property of the user's input
      }
    }],
  });
  ```

  REST API

  ```http REST API theme={null}
  POST https://api.useparagon.com/projects/<Paragon Project ID>/sdk/actions

  Authorization: Bearer <Paragon User Token>
  Content-Type: application/json

  {
    "action": "salesforce",
    "sourceKey": "cachedFields",
    "parameters": [{
      "key": "recordTypes",
      "source": {
        "type": "VALUE",
        "value": "Task"
      }
    }],
    "paginationParameters": {
      "pageCursor": 0,
      "search": ""
    }
  }
  ```
</CodeGroup>

### <span id="getintegrationconfig">.getIntegrationConfig(integrationType: string)</span>

Call `getIntegrationConfig` to get the user-facing descriptions, User Settings, and Workflows associated with any integration.

<CodeGroup>
  ```js JavaScript SDK expandable theme={null}
  paragon.getIntegrationConfig("slack");

  // Returns:
  {
    "shortDescription": "Send notifications to Slack",
    "longDescription": "Connect your Slack workspace to receive notifications and alerts in Slack. Stay connected to important activity by bringing it all together in your Slack workspace.\n\nOur Slack integration enables you to:\n\n• Receive alerts and notifications in your Slack workspace\n• Notify or DM specific team members based on certain activity",
    "availableUserSettings": [
      {
        "id": "2d5662c9-6750-46c2-8588-2ac904532efb",
        "type": "DYNAMIC_ENUM",
        "title": "Channel",
        "required": false,
        "sourceType": "channels"
      }
    ],
    "availableWorkflows": [
      {
        "id": "2248335c-671c-47e4-b9a0-3641a9f2d301",
        "inputs": [],
        "infoText": "Send a Slack notification when a Task is created",
        "defaultEnabled": false,
        "description": "Send Slack Notification"
      }
    ],
    "hiddenWorkflows": []
  }
  ```

  ```http REST API expandable theme={null}
  GET https://api.useparagon.com/projects/<Paragon Project ID>/sdk/integrations

  Authorization: Bearer <Paragon User Token>
  Content-Type: application/json

  // Response:
  [{
    "id": "2f08e65f-d924-42ab-9618-b6023d82ffbd",
    "projectId": "908f4c5e-6394-46a5-9355-3f729edbd160",
    "customIntegrationId": null,
    "type": "slack",
    "isActive": true,
    "configs": [
      {
        "id": "3ebcc179-a1a6-447f-8dc9-5017f40f08ef",
        "values": {
          "overview": "####Our Slack integration enables you to:\n   \n\n• Receive alerts and notifications in your Slack workspace\n• Notify or DM specific team members based on certain activity",
          "sharedMeta": {},
          "accentColor": "#4A154B",
          "description": "Send notifications to Slack",
          "workflowMeta": {}
        }
      },
    ],
    "workflows": [
      {
        "id": "1b22193b-e355-458d-b6a3-5e5516edb588",
        "description": "Send Updates to Slack",
        "projectId": "908f4c5e-6394-46a5-9355-3f729edbd160",
        "integrationId": "2f08e65f-d924-42ab-9618-b6023d82ffbd",
        "steps": []
      }
    ],
    "customIntegration": null,
    "hasCredential": true,
    "connectedUserLimitOnDevCred": 0,
    "connectedUserLimitReached": true,
    "name": "Slack",
    "brandColor": "#4A154B",
    "needPreOauthInputs": false,
    "providerType": "slack",
    "authenticationType": "oauth"
  }]
  ```
</CodeGroup>

### <span id="getintegrationmetadata">.getIntegrationMetadata(integrationType: string?)</span>

Call `.getIntegrationMetadata` to get the `name`, `brandColor`, and `icon`, for any of your active integration providers. This is a great way to create your integrations page!

<CodeGroup>
  ```JS JavaScript SDK theme={null}
  paragon.getIntegrationMetadata();

  // Returns:
  [
    {
      type: 'salesforce',
      name: 'Salesforce',
      brandColor: '#057ACF',
      icon: 'https://cdn.useparagon.com/2.35.0/dashboard/public/integrations/salesforce.svg'
    },
    {
      type: 'hubspot',
      name: 'Hubspot',
      brandColor: '#F67600',
      icon: 'https://cdn.useparagon.com/2.35.0/dashboard/public/integrations/hubspot.svg'
    },
    {
      type: 'slack',
      name: 'Slack',
      brandColor: '#4A154B',
      icon: 'https://cdn.useparagon.com/2.35.0/dashboard/public/integrations/slack.svg'
    }
  ]
  ```

  ```http REST API theme={null}
  GET https://api.useparagon.com/projects/<Paragon Project ID>/sdk/metadata

  Authorization: Bearer <Paragon User Token>
  Content-Type: application/json

  // Response
  [
    {
      "type": "salesforce",
      "name": "Salesforce",
      "brandColor": "#057ACF",
      "icon": "https://cdn.useparagon.com/2.35.0/dashboard/public/integrations/salesforce.svg"
    },
    {
      "type": "hubspot",
      "name": "Hubspot",
      "brandColor": "#F67600",
      "icon": "https://cdn.useparagon.com/2.35.0/dashboard/public/integrations/hubspot.svg"
    },
    {
      "type": "slack",
      "name": "Slack",
      "brandColor": "#4A154B",
      "icon": "https://cdn.useparagon.com/2.35.0/dashboard/public/integrations/slack.svg"
    }
  ]
  ```
</CodeGroup>

### <span id="getuser">.getUser() → ParagonUser</span>

Call `.getUser` to retrieve the currently authenticated user and their connected integration state.

A **ParagonUser** is an object shaped like:

<CodeGroup>
  ```javascript JavaScript SDK theme={null}
  paragon.getUser();

  // Response
  {
  	authenticated: true,
  	userId: "xyz", // The user ID you specified in the signed JWT
  	integrations: {
  		salesforce: {
  			configuredWorkflows: {},
  			credentialId: "987654-56a7-89b1-cd23-456789abcdef",
  			credentialStatus: "VALID",
  			enabled: true
  			providerData: {
  				instanceURL: "https://mycompany.my.salesforce.com"
  			},
  			providerId: "1234567890"
  		},
  		shopify: {
  			configuredWorkflows: {},
  			enabled: false
  		}
  	}
  }
  ```

  ```http REST API theme={null}
  GET https://api.useparagon.com/projects/<Paragon Project ID>/sdk/me

  Authorization: Bearer <Paragon User Token>
  Content-Type: application/json

  // Response
  {
  	authenticated: true,
  	userId: "xyz", // The user ID you specified in the signed JWT
  	integrations: {
  		salesforce: {
  			configuredWorkflows: {},
  			credentialId: "987654-56a7-89b1-cd23-456789abcdef",
  			credentialStatus: "VALID",
  			enabled: true
  			providerData: {
  				instanceURL: "https://mycompany.my.salesforce.com"
  				},
  			providerId: "1234567890"
  		},
  		shopify: {
  			configuredWorkflows: {},
  			enabled: false
  		}
  	}
  }
  ```
</CodeGroup>

If the user is not authenticated, you'll receive back only `{ authenticated: false }` instead. Please check the `authenticated` property before using the `user.integrations` field.

### <span id="event">.event(name: string, json: JSON)</span>

App Events can be sent from your application using the Paragon SDK or REST API. In both cases, you must pass two parameters:

* **name** - the event name defined in your App Event

* **payload** - the event payload that should match the event schema defined in your App Event

See the code examples below for how to send App Events using the Paragon SDK or API.

<CodeGroup>
  ```javascript JavaScript SDK theme={null}
  var eventName = "Contact Created";
  var eventPayload = { "name": "Brandon", "email": "b@useparagon.com" };

  // Called once during your user's session
  paragon.authenticate("project-id", <Paragon User Token>);

  // Trigger the "Contact Created" App Event
  paragon.event(eventName, eventPayload);
  ```

  ```http REST API theme={null}
  // Trigger the "Contact Created" App Event
  POST https://api.useparagon.com/projects/<Paragon Project ID>/sdk/events/trigger

  // Headers
  Authorization: Bearer <Paragon User Token>
  Content-Type: application/json

  // Body
  {
      "name": "Contact Created",
      "payload": {
          "name": "Brandon",
          "email": "b@useparagon.com"
      }
  }
  ```
</CodeGroup>

When sending live events from your application, Paragon will not validate that your event payload matches the defined event schema.

### <span id="installintegration">.installIntegration(integrationType: string, installOptions?: InstallOptions) -> Promise\<IntegrationInstallEvent></span>

<Info>
  This function should be used only if you are using your [own components](/connect-portal/headless-connect-portal) to show connected integrations and their status, instead of the Connect Portal.

  Otherwise, you can use [the `.connect` function](/apis/api-reference#connect).
</Info>

The `.installIntegration` can be used to start the connection process for an integration *without* the Connect Portal appearing over your user interface. You can find the `integrationType` identifier you need in the Overview page for the integration.

This function resolves with the `IntegrationInstallEvent` in the same format available in `paragon.subscribe`. You can use this to get the newly created credential by awaiting the returned Promise.

This function rejects the returned Promise if the integration is already installed for the authenticated user.

```js JavaScript SDK theme={null}
const { credential } = await paragon.installIntegration("googledrive");
```

**Note**: If the integration specified by `integrationType` requires API keys or post-authentication options, the Connect Portal will still appear to capture those values from your user at that time. The Connect Portal will automatically be dismissed after those values are entered.

This function accepts the same optional install options as [`.connect()`](/apis/api-reference#connect).

### .subscribe(eventName: string, handler: Function)

Call `.subscribe` to subscribe to different events and changes from the Paragon SDK. You can find the possible `eventNames` below:

| Event Type                | Usage in `.subscribe()`    | Usage in `.connect()` |
| ------------------------- | -------------------------- | --------------------- |
| **Integration enabled**   | `"onIntegrationInstall"`   | `"onInstall"`         |
| **Integration disabled**  | `"onIntegrationUninstall"` | `"onUninstall"`       |
| **Workflow state change** | `"onWorkflowChange"`       | `"onWorkflowChange"`  |
| **Connect Portal opened** | `"onPortalOpen"`           | `"onOpen"`            |
| **Connect Portal closed** | `"onPortalClose"`          | `"onClose"`           |

Subscribing to SDK Events applies to all integrations *globally*. Specifying callbacks to `.connect()` only applies to a currently open Connect Portal *locally*.

See the code examples below for how to subscribe to events using the Paragon SDK.

<CodeGroup>
  ```typescript Integration Enabled / Disabled theme={null}
  type IntegrationInstallEvent = {
    integrationId: string;
    integrationType: VisibleConnectAction;
    credential: Credential;
    credentialId: string;
  };

  // Using global subscribe
  paragon.subscribe(
    "onIntegrationInstall",
    (event: IntegrationInstallEvent, user: AuthenticatedConnectUser) => {
      /* ... */
    }
  );
  ```

  ```typescript Workflow State Changed theme={null}
  type WorkflowStateChangeEvent = {
    integrationId: string;
    workflowId: string;
  };

  // Using global subscribe
  paragon.subscribe(
    "onWorkflowChange",
    (event: WorkflowStateChangeEvent, user: AuthenticatedConnectUser) => {
      /* ... */
    }
  );
  ```

  ```typescript Connect Portal Opened / Closed theme={null}
  type PortalOpenEvent = {
    integrationId: string;
    integrationType: VisibleConnectAction;
  };

  type PortalCloseEvent = {
    integrationId: string;
    integrationType: VisibleConnectAction;
  };

  // Using global subscribe
  paragon.subscribe(
    "onPortalOpen",
    (event: PortalOpenEvent, user: AuthenticatedConnectUser) => {
      /* ... */
    }
  );
  paragon.subscribe(
    "onPortalClose",
    (event: PortalCloseEvent, user: AuthenticatedConnectUser) => {
      /* ... */
    }
  );
  ```
</CodeGroup>

Alternatively, you can subscribe `onOpen`, `onClose`, `onUninstall` , and `onWorkflowChange` as a one-time event locally.

<CodeGroup>
  ```typescript Integration Enabled / Disabled theme={null}
  type IntegrationInstallEvent = {
    integrationId: string;
    integrationType: VisibleConnectAction;
    credential: Credential;
    credentialId: string;
  };

  // Using local call to paragon.connect
  paragon.connect("<integration>", {
    onInstall: (
      event: IntegrationInstallEvent,
      user: AuthenticatedConnectUser
    ) => {
      /* ... */
    },
  });
  ```

  ```typescript Workflow State Changed theme={null}
  type WorkflowStateChangeEvent = {
    integrationId: string;
    workflowId: string;
  };

  // Using local call to paragon.connect
  paragon.connect("<integration>", {
    onWorkflowChange: (
      event: WorkflowStateChangeEvent,
      user: AuthenticatedConnectUser
    ) => {
      /* ... */
    },
  });
  ```

  ```typescript Connect Portal Opened / Closed theme={null}
  type PortalOpenEvent = {
    integrationId: string;
    integrationType: VisibleConnectAction;
  };

  type PortalCloseEvent = {
    integrationId: string;
    integrationType: VisibleConnectAction;
  };

  // Using local call to paragon.connect
  paragon.connect("<integration>", {
    onOpen: (event: PortalOpenEvent, user: AuthenticatedConnectUser) => {
      /* ... */
    },
    onClose: (event: PortalCloseEvent, user: AuthenticatedConnectUser) => {
      /* ... */
    },
  });
  ```
</CodeGroup>

### .request(integrationType: string, path: string, requestOptions?: RequestInit ) → Promise

Call `.request` to send an API request to a third-party integration on behalf of one of your users.

Every integration in your dashboard has a code example of using `paragon.request`, which takes the following arguments:

* `integrationType`: The short name for the integration. i.e. "salesforce" or "googleCalendar". You can find this string on the Overview tab of the integration you want to access, on your Paragon dashboard.

* `path`: The path (without the hostname) of the API request you are trying to access. An example might be: "/v1/charges" for Stripe's charge API or "chat.postMessage" for Slack's Web API.

* `requestOptions` (optional): Request options to include, such as:

  * `body`: An object representing JSON contents of the request.

  * `method`: An HTTP verb such as "GET" or "POST". Defaults to GET.

  * `headers`: Additional HTTP headers to include in the request.

  If `requestOptions` is omitted, the SDK issues a `GET` request without a body.

The function returns a promise for the request output, which will have a shape that varies depending on the integration and API endpoint.

<CodeGroup>
  ```typescript JavaScript SDK theme={null}
  await paragon.request('slack', '/chat.postMessage', {
  	method: 'POST',
  	body: {
  		channel: 'CXXXXXXX0' // Channel ID,
  		text: 'This message was sent with Paragon Connect :exploding_head:'
  	}
  });

  // -> Responds with { ok: true }, and sends a message :)
  ```

  ```http REST API theme={null}
  POST https://proxy.useparagon.com/projects/<Paragon Project ID>/sdk/proxy/slack/chat.postMessage

  Authorization: Bearer <Paragon User Token>
  Content-Type: application/json

  {
      "channel": "CXXXXXXX0",
      "text": "This message was sent with Paragon Connect :exploding_head:"
  }

  // -> Responds with { output: { ok: true }}, and sends a message :)
  ```
</CodeGroup>

### .setUserMetadata(meta: object)

Call `.setUserMetadata()` to associate the authenticated user with metadata from your application. This metadata can be accessed with `.getUser()` or retrieved over the API.

<CodeGroup>
  ```typescript JavaScript SDK theme={null}
  paragon.setUserMetadata({
    Name: "Sean V",
    Email: "sean@useparagon.com",
    apiKey: "key_Y0kBVldPFInxK",
  });
  ```

  **Request**

  ```http REST API theme={null}
  PATCH https://api.useparagon.com/projects/<Project ID>/sdk/me

  // Headers
  Authorization: <Paragon User Token>
  Content-Type: application/json

  // Body
  { "meta": { "Email": "sean@useparagon.com", "apiKey": "key_Y0kBVldPFInxK" } }
  ```
</CodeGroup>

### <span id="uninstallintegration">.uninstallIntegration(integrationType: string) -> Promise</span>

Call `.uninstallIntegration()` to disconnect an integration for the authenticated user.

When an integration is disconnected, workflows for that integration will stop running for the authenticated user and any saved User Settings will be cleared.

<CodeGroup>
  ```typescript JavaScript SDK theme={null}
  // Use the integration name, as used in paragon.connect();
  await paragon.uninstallIntegration("salesforce");
  ```

  Get the ID of the integration you want to disconnect, with the `/sdk/integrations` endpoint:

  **Request**

  ```http REST API theme={null}
  GET https://api.useparagon.com/projects/<Project ID>/sdk/integrations

  // Headers
  Authorization: Bearer <Paragon User Token>

  // Response
  [
      { "id": "<Integration ID>", "type": "salesforce", ... },
      {...}
  ]

  // The <Integration ID> can be used to disconnect the integration for the user:

  DELETE https://api.useparagon.com/projects/<Project ID>/sdk/integrations/<Integration ID>

  // Headers
  Authorization: Bearer <Paragon User Token>
  ```
</CodeGroup>

### <span id="updateintegrationusersettings">.updateIntegrationUserSettings(integrationType: string, userSettingsUpdate: object, options?: CredentialConfigOptions)</span>

Call `.updateIntegrationUserSettings()` to update any integration-level [User Settings](/connect-portal/workflow-user-settings) for your Connected User.

**Arguments:**

<ParamField path="integrationType" type="string" required>
  An integration type string, like `salesforce`.
</ParamField>

<ParamField path="userSettingsUpdate" type="object" required>
  A partial update object where the keys are the `id` properties of User Settings objects (which you can get from [`getIntegrationConfig`](#getintegrationconfig)) and the values are the user's selection for the matching input type.

  Any keys that are not included in the object will not be updated.

  The type for each value will depend on the input type. See [Input Types Reference](/connect-portal/input-types-reference) to see the value type for each input.

  ```json Example theme={null}
  {
    "1f7474a5-8b8e-4c25-8d44-29f20aec3fe4": "general"
  }
  ```
</ParamField>

<ParamField path="options" type="CredentialConfigOptions | undefined">
  Optionally specify a Credential and Configuration to target, if using [Multi-Account Authorization](/apis/api-reference/multi-account-authorization) or [Multi-Configuration](/apis/api-reference/multi-configuration).

  <Accordion title="Show child properties">
    <ParamField path="selectedCredentialId" type="string">
      The Credential ID (a UUID) of the connected account you want to update, if using [Multi-Account Authorization](/apis/api-reference/multi-account-authorization).
    </ParamField>

    <ParamField path="selectedConfigurationId" type="string">
      The Configuration ID (a UUID or an External ID prefixed with `ext:`), if using [Multi-Configuration](/apis/api-reference/multi-configuration).
    </ParamField>
  </Accordion>
</ParamField>

### <span id="updateworkflowstate">.updateWorkflowState(workflowStateUpdate: object, options?: CredentialConfigOptions)</span>

Call `.updateWorkflowState()` to enable or disable workflows for a user.

**Arguments:**

<ParamField path="workflowStateUpdate" type="object" required>
  A partial update object where keys are workflow IDs and values are `true` or `false`. Any workflow IDs not included in this object will not be updated in this call.

  ```json Example theme={null}
  {
    "bb89897b-ec2a-4118-b091-c12713c6bffa": true,
    "487c67e1-bc3f-406e-acc4-085f897dc564": false,
  }
  ```
</ParamField>

<ParamField path="options" type="CredentialConfigOptions | undefined">
  Optionally specify a Credential and Configuration to target, if using [Multi-Account Authorization](/apis/api-reference/multi-account-authorization) or [Multi-Configuration](/apis/api-reference/multi-configuration).

  <Accordion title="Show child properties">
    <ParamField path="selectedCredentialId" type="string">
      The Credential ID (a UUID) of the connected account you want to update, if using [Multi-Account Authorization](/apis/api-reference/multi-account-authorization).
    </ParamField>

    <ParamField path="selectedConfigurationId" type="string">
      The Configuration ID (a UUID or an External ID prefixed with `ext:`), if using [Multi-Configuration](/apis/api-reference/multi-configuration).
    </ParamField>
  </Accordion>
</ParamField>

### <span id="updateworkflowusersettings">.updateWorkflowUserSettings(integrationType: string, workflowId: string, userSettingsUpdate: object, options?: CredentialConfigOptions)</span>

Call `.updateWorkflowUserSettings()` to update any workflow-level [User Settings](/connect-portal/workflow-user-settings) for your Connected User.

**Arguments:**

<ParamField path="integrationType" type="string" required>
  An integration type string, like `salesforce`.
</ParamField>

<ParamField path="workflowId" type="string" required>
  The ID of the Workflow that the workflow-level User Setting you are modifying belongs to. If you are trying to modify an integration-level User Setting, call [`updateIntegrationUserSettings`](#updateintegrationusersettings) instead.
</ParamField>

<ParamField path="userSettingsUpdate" type="object" required>
  A partial update object where the keys are the `id` properties of User Settings objects (which you can get from [`getIntegrationConfig`](#getintegrationconfig)) and the values are the user's selection for the matching input type.

  Any keys that are not included in the object will not be updated.

  The type for each value will depend on the input type. See [Input Types Reference](/connect-portal/input-types-reference) to see the value type for each input.

  ```json Example theme={null}
  {
    "1f7474a5-8b8e-4c25-8d44-29f20aec3fe4": "general"
  }
  ```
</ParamField>

<ParamField path="options" type="CredentialConfigOptions | undefined">
  Optionally specify a Credential and Configuration to target, if using [Multi-Account Authorization](/apis/api-reference/multi-account-authorization) or [Multi-Configuration](/apis/api-reference/multi-configuration).

  <Accordion title="Show child properties">
    <ParamField path="selectedCredentialId" type="string">
      The Credential ID (a UUID) of the connected account you want to update, if using [Multi-Account Authorization](/apis/api-reference/multi-account-authorization).
    </ParamField>

    <ParamField path="selectedConfigurationId" type="string">
      The Configuration ID (a UUID or an External ID prefixed with `ext:`), if using [Multi-Configuration](/apis/api-reference/multi-configuration).
    </ParamField>
  </Accordion>
</ParamField>

### .workflow(workflowId: string, options: FetchOptions)

Call `.workflow()` to trigger a Paragon workflow that sends a custom response back to your app. Note: The workflow must be enabled and use a Request-type trigger.

<CodeGroup>
  ```javascript Javascript SDK theme={null}
  // Called once during your user's session
  paragon.authenticate("project-id", <Paragon User Token>)

  // Trigger the "Lead Created" workflow
  await paragon.workflow("<workflow_id>", {
    "body": {
      "email": "bowie@useparagon.com",
      "first_name": "Bowie",
      "last_name": "Foo"
    }
  });

  ```

  ```http REST API theme={null}
  // Trigger the "Lead Created" Workflow
  POST https://api.useparagon.com/projects/<Paragon Project ID>/sdk/triggers/<Workflow ID>

  Authorization: Bearer <Paragon User Token>
  Content-Type: application/json

  {
    "email": "bowie@useparagon.com",
    "first_name": "Bowie",
    "last_name": "Foo
  }
  ```
</CodeGroup>

### Get project's integrations

Returns a list of the integrations enabled for the Paragon project by the ID in the URL.

* Includes the Connect Portal configuration for each integration (as `.configs`) and the Workflows associated with each integration (as `.workflows`)

You can use [`getIntegrationMetadata`](#getintegrationmetadata) and [`getIntegrationConfig`](#getintegrationconfig) when using the JavaScript SDK.

```http REST API expandable theme={null}
GET https://api.useparagon.com/projects/<Paragon Project ID>/sdk/integrations

Authorization: Bearer <Paragon User Token>
Content-Type: application/json

// Example response (may include more than is in this list):

[{
  "id": "2f08e65f-d924-42ab-9618-b6023d82ffbd",
  "projectId": "908f4c5e-6394-46a5-9355-3f729edbd160",
  "customIntegrationId": null,
  "type": "slack",
  "isActive": true,
  "configs": [
    {
      "id": "3ebcc179-a1a6-447f-8dc9-5017f40f08ef",
      "values": {
        "overview": "####Our Slack integration enables you to:\n   \n\n• Receive alerts and notifications in your Slack workspace\n• Notify or DM specific team members based on certain activity",
        "sharedMeta": {},
        "accentColor": "#4A154B",
        "description": "Send notifications to Slack",
        "workflowMeta": {}
      }
    },
  ],
  "workflows": [
    {
      "id": "1b22193b-e355-458d-b6a3-5e5516edb588",
      "description": "Send Updates to Slack",
      "projectId": "908f4c5e-6394-46a5-9355-3f729edbd160",
      "integrationId": "2f08e65f-d924-42ab-9618-b6023d82ffbd",
      "steps": []
    }
  ],
  "customIntegration": null,
  "hasCredential": true,
  "connectedUserLimitOnDevCred": 0,
  "connectedUserLimitReached": true,
  "name": "Slack",
  "brandColor": "#4A154B",
  "needPreOauthInputs": false,
  "providerType": "slack",
  "authenticationType": "oauth"
}]
```

### <span id="get-connect-credentials">Get user's Connect credentials</span>

Returns a list of the user's Connect credentials (i.e., the accounts connected and authorized by the end user).

* The **providerId** is the authenticated user's ID assigned by their integration provider (e.g. for a Salesforce integration, this would be the user's Salesforce user ID)

This method is currently available via REST API only.

```http REST API theme={null}
GET https://api.useparagon.com/projects/<Paragon Project ID>/sdk/credentials

Authorization: Bearer <Paragon User Token>
Content-Type: application/json

// Example response (may include more than is in this list):

[{
  "id": "00da4146-7ac4-4253-a8f7-96849b8137d9",
  "dateCreated": "2021-03-24T12:19:21.511Z",
  "dateUpdated": "2021-03-24T12:19:28.512Z",
  "dateDeleted": null,
  "projectId": "db06d291-ba2c-41c5-9a12-9362abfd6228",
  "integrationId": "95bedc9f-6a22-4855-b08d-e68dc073ad91",
  "personaId": "0563109f-5e71-46c5-8483-1ac8c0913d6c",
  "config": {
    "configuredWorkflows": {
      "3eb95154-3c7b-413c-bf14-ba367d95b53f": {
        "enabled": true,
        "settings": {
					"example-input-id": "example value"
				}
      }
    }
  },
  "isPreviewCredential": false,
  "providerId": "50150244515"
}]
```

### Update user's Connect credential

Updates the user's connected integration account, including any settings and configured workflows.

This endpoint updates by replacement with respect to the `config` property, so this endpoint should only be used after retrieving the existing value (which can be done by using the above endpoint: [Get user's Connect credentials](/apis/api-reference#get-connect-credentials)).

Alternatively, you can use the SDK to update User Settings or workflow enablements:

* [`updateIntegrationUserSettings`](/apis/api-reference#updateintegrationusersettings): Update integration-level User Settings.
* [`updateWorkflowUserSettings`](/apis/api-reference#updateworkflowusersettings): Update workflow-level User Settings.
* [`updateWorkflowState`](/apis/api-reference#updateworkflowstate): Update workflow enablements.

```http REST API theme={null}
PATCH https://api.useparagon.com/projects/<Paragon Project ID>/sdk/credentials/<Connect Credential ID>

Authorization: Bearer <Paragon User Token>
Content-Type: application/json

// Body: Example showing <Workflow ID> being enabled
{
    "config": {
        "configuredWorkflows": {
            ...
            "<Workflow ID>": {
                "enabled": true,
                "settings": {}
            }
        },
        "sharedSettings": {...}
    }
}
```

**Note**: In the above example, the existing value for `config` must be provided in full, with the intended changes applied. This is because `config` will be updated by replacement.

### <span id="setdatasources">.setDataSources(config: SetDataSourcesConfig)</span>

Call `.setDataSources` to register custom data sources for dropdown and field mapping inputs when using the [Headless Connect Portal](/connect-portal/headless-connect-portal). This can be used in place of passing `dropdowns` and `mapObjectFields` inline with `.connect()`, for Headless Connect Portal implementations.

Data sources can be registered globally (applied to all integrations) or for specific integrations. When an integration-specific source exists, it takes priority over a global source with the same key.

This function should be called once after [`setHeadless(true)`](#setheadless) and before rendering any inputs.

**Arguments:**

<ParamField path="config" type="SetDataSourcesConfig" required>
  <Accordion title="Show child properties" defaultOpen>
    <ParamField path="dropdowns" type="Record<string, CustomDropdownField[] | CustomDropdownOptions>">
      Global custom dropdown data sources, keyed by the dropdown `key` identifier. Values can be either a static array of `CustomDropdownField[]` options (objects with `label` and `value` strings), or a `CustomDropdownOptions` object for dynamic loading:

      ```js Static dropdown options theme={null}
      paragon.setDataSources({
        dropdowns: {
          my_custom_dropdown: [
            { label: "Option A", value: "a" },
            { label: "Option B", value: "b" },
          ],
        },
      });
      ```

      <Accordion title="Show child properties (CustomDropdownOptions)">
        <ParamField path="loadOptions" type="(cursor?: string, search?: string) => Promise<{ options: CustomDropdownField[], nextPageCursor: string | null }>" required>
          A function that returns dropdown options with support for pagination and search. Called by the SDK when options need to be loaded or refreshed.
        </ParamField>

        <ParamField path="refreshOnOpen" type="boolean">
          If `true`, the dropdown options will be reloaded every time the dropdown is opened. Useful for dependent dropdowns where options depend on other input values. Defaults to `false`.
        </ParamField>

        ```js Dynamic dropdown with loader expandable theme={null}
        paragon.setDataSources({
          dropdowns: {
            my_dynamic_dropdown: {
              loadOptions: async (cursor, search) => {
                const response = await fetch(`/api/options?cursor=${cursor}&search=${search}`);
                const data = await response.json();
                return {
                  options: data.items,
                  nextPageCursor: data.nextCursor,
                };
              },
            },
          },
        });
        ```
      </Accordion>
    </ParamField>

    <ParamField path="mapObjectFields" type="Record<string, DynamicMappingField[] | DynamicMappingOptions | DynamicFieldMappingConfig>">
      Global field mapping data sources, keyed by field mapping name. Values can be one of the following:

      <Accordion title="Show child properties (DynamicMappingField)">
        **Option 1: `DynamicMappingField[]`** - Static array of mapping options.

        <ParamField path="label" type="string" required>
          The display label for the field.
        </ParamField>

        <ParamField path="value" type="string" required>
          The value identifier for the field.
        </ParamField>
      </Accordion>

      <Accordion title="Show child properties (DynamicMappingOptions)">
        **Option 2: `DynamicMappingOptions`** — Configurable mapping behavior with static fields.

        <ParamField path="fields" type="DynamicMappingField[]" required>
          The list of available fields (objects with `label` and `value` strings).
        </ParamField>

        <ParamField path="defaultFields" type="string[]">
          Field values that should be selected by default.
        </ParamField>

        <ParamField path="userCanRemoveMappings" type="boolean">
          Whether users can remove field mappings.
        </ParamField>

        <ParamField path="userCanCreateFields" type="boolean">
          Whether users can create new fields.
        </ParamField>
      </Accordion>

      <Accordion title="Show child properties (DynamicFieldMappingConfig)">
        **Option 3: `DynamicFieldMappingConfig`** — Fully dynamic field mapping with loader functions for fetching object types and fields at runtime.

        <ParamField path="objectTypes.get" type="(cursor?: string, search?: string) => Promise<{ options: { label: string, value: string }[], nextPageCursor: string | null }>" required>
          A loader function to fetch available object types with pagination and search support.
        </ParamField>

        <ParamField path="integrationFields.get" type="(params: { objectType: string }, cursor?: string, search?: string) => Promise<{ options: { label: string, value: string }[], nextPageCursor: string | null }>" required>
          A loader function to fetch available fields for a given object type with pagination and search support.
        </ParamField>

        <ParamField path="applicationFields" type="object">
          Optional configuration for application-side fields.

          <Accordion title="Show child properties">
            <ParamField path="fields" type="{ label: string, value: string }[]" required>
              The list of application fields available for mapping.
            </ParamField>

            <ParamField path="defaultFields" type="string[]">
              Field values that should be selected by default.
            </ParamField>

            <ParamField path="userCanRemoveMappings" type="boolean">
              Whether users can remove field mappings.
            </ParamField>

            <ParamField path="userCanCreateFields" type="boolean">
              Whether users can create new fields.
            </ParamField>
          </Accordion>
        </ParamField>

        ```js Field mapping with BYO loaders expandable theme={null}
        paragon.setDataSources({
          mapObjectFields: {
            myFieldMapping: {
              objectTypes: {
                get: async (cursor, search) => {
                  const response = await fetch(`/api/object-types?cursor=${cursor}&search=${search}`);
                  const data = await response.json();
                  return { options: data.items, nextPageCursor: data.nextCursor };
                },
              },
              integrationFields: {
                get: async ({ objectType }, cursor, search) => {
                  const response = await fetch(
                    `/api/fields?objectType=${objectType}&cursor=${cursor}&search=${search}`
                  );
                  const data = await response.json();
                  return { options: data.items, nextPageCursor: data.nextCursor };
                },
              },
              applicationFields: {
                fields: [
                  { label: "Name", value: "name" },
                  { label: "Email", value: "email" },
                ],
              },
            },
          },
        });
        ```
      </Accordion>
    </ParamField>

    <ParamField path="integrationSpecificSources" type="Record<string, { dropdowns?, mapObjectFields? }>">
      Integration-specific data sources that take priority over global sources. Keyed by integration type (e.g. `"salesforce"`), with the same `dropdowns` and `mapObjectFields` structure.

      ```js Integration-specific sources expandable theme={null}
      paragon.setDataSources({
        dropdowns: {
          departments: [
            { label: "Engineering", value: "eng" },
            { label: "Sales", value: "sales" },
          ],
        },
        integrationSpecificSources: {
          salesforce: {
            dropdowns: {
              departments: [
                { label: "Engineering", value: "engineering" },
                { label: "Sales", value: "sales-dept" },
                { label: "Marketing", value: "marketing" },
              ],
            },
          },
        },
      });
      ```
    </ParamField>
  </Accordion>
</ParamField>

### <span id="setheadless">.setHeadless(headless: boolean)</span>

Call `.setHeadless` to enable or disable Headless mode for the SDK. When headless mode is enabled, the SDK will not render the Connect Portal UI and will instead expose functions for you to build your own UI.

```js theme={null}
paragon.setHeadless(true);
```

This should be called once after SDK initialization. See the [Headless Connect Portal](/connect-portal/headless-connect-portal) guide for more details.

## installFlow

Use `installFlow` when implementing the [Headless Connect Portal](/connect-portal/headless-connect-portal) to guide your user through the installation process for an integration.

### <span id="installflowstart">installFlow\.start(integrationType, options)</span>

Call `installFlow.start()` to begin an install flow for an integration. [See an example call](/connect-portal/headless-connect-portal#example-install-flow).

**Arguments:**

<ParamField path="integrationType" type="string" required>
  The integration type string, like `salesforce`.
</ParamField>

<ParamField path="options" type="object" required>
  <Accordion title="Show child properties" defaultOpen>
    <ParamField path="onNext(nextStage)" type="function">
      This callback is called when the install flow is ready to move to the next stage.

      Your app must render the appropriate UI for each stage, so that your user can provide the necessary details in that stage to connect their account.

      <Accordion title="Show callback arguments">
        <ParamField path="nextStage" type="InstallFlowStage">
          The install flow stage for your app to render. See [InstallFlowStage](#installflowstage) for more details.
        </ParamField>
      </Accordion>
    </ParamField>

    <ParamField path="onComplete()" type="function">
      This callback is called when the install flow completes successfully.
    </ParamField>

    <ParamField path="onError(error, context)" type="function">
      This callback is called when the install flow fails, with an error object and error context.

      <Accordion title="Show callback arguments">
        <ParamField path="error" type="Error">
          The error object. You can read the `.name` of the error object to identify one of the following error types:

          * `OAuthBlockedError`: The browser blocked the OAuth prompt from appearing. This may require the user to allow popups in their browser settings.
          * `OAuthTimeoutError`: The OAuth prompt took longer than `oauthTimeout` milliseconds (as provided in `options`) to complete.
          * `UserNotAuthenticatedError`: The user is not authenticated with the Paragon SDK. Verify that `paragon.authenticate()` has been called before starting the install flow.
          * `NoActiveInstallFlowError`: An install flow function was called, but no install flow is currently active. Call `start()` to start an install flow.
          * `HeadlessModeNotEnabledError`: Headless Connect Portal is not enabled. Call `paragon.setHeadless(true)` to enable Headless mode.
          * `IntegrationNotFoundError`: The provided integration type is not found or has [not been enabled](/getting-started/displaying-the-connect-portal#activating-the-integration) in your Paragon project.
        </ParamField>

        <ParamField path="context" type="ErrorContext | null">
          The error context object.

          <Accordion title="Show child properties">
            <ParamField path="stage" type="InstallFlowStage">
              The stage that the install flow was on when the error occurred.

              **One of**: `accountType`, `preOptions`, `postOptions`, `instruction`.
            </ParamField>
          </Accordion>
        </ParamField>
      </Accordion>
    </ParamField>

    <ParamField path="oauthTimeout" type="number">
      The number of milliseconds to wait for an OAuth prompt to complete. If the user does not complete the OAuth prompt within this time, the install flow will fail, and the `onError` callback will be called.

      If not provided, there will be no timeout for the OAuth prompt.
    </ParamField>

    <ParamField path="allowMultipleCredentials" type="boolean">
      Set to `true` if using [Multi-Account Authorization](/apis/api-reference/multi-account-authorization). This will allow users to connect multiple accounts under one integration type.

      Defaults to `false`.
    </ParamField>

    <ParamField path="selectedCredentialId" type="string">
      Set this parameter to *replace* an account by a selected Credential ID instead of connecting a new account.

      This can be used to prompt a user to reconnect a credential if authorization has been revoked and the `status` of the credential is `INVALID`.
    </ParamField>

    <ParamField path="overrideRedirectUrl" type="string">
      Set this parameter to your Redirect Page URL for integrations like [Google Drive](/resources/integrations/google-drive#setting-up-a-redirect-page-in-your-app).
    </ParamField>
  </Accordion>
</ParamField>

### <span id="setaccounttype">installFlow\.setAccountType(accountType)</span>

Call `installFlow.setAccountType(accountType)` when the user selects an account type in the `AccountTypeStage`.

**Arguments:**

<ParamField path="accountType" type="string" required>
  The account type to set. This should be the `id` property of the Account Type option that the user selected.
</ParamField>

### <span id="setpreoptions">installFlow\.setPreOptions(values)</span>

Call `installFlow.setPreOptions(values)` when the user finishes providing inputs in the `PreOptionsStage`.

This returns a Promise that resolves when the values are saved. Upon success, the install flow will move to the next stage and call `onNext`. If there is no stage after the `PreOptionsStage`, the install flow will call `onComplete`.

**Arguments:**

<ParamField path="values" type="object" required>
  The values to set for the inputs in the `PreOptionsStage`.

  This should be an object, where the keys are `id`s of the inputs in the `PreOptionsStage`, and the values are the values that the user provided for each input.

  ```js Example (Shopify) theme={null}
  await paragon.installFlow.setPreOptions({
    "SHOP_NAME": "my-shop"
  });
  ```
</ParamField>

### <span id="setpostoptions">installFlow\.setPostOptions(values)</span>

Call `installFlow.setPostOptions(values)` when the user finishes providing inputs in the `PostOptionsStage`.

This returns a Promise that resolves when the values are saved. Upon success, the install flow will be completed and call `onComplete`.

**Arguments:**

<ParamField path="values" type="object" required>
  The values to set for the inputs in the `PostOptionsStage`.

  This should be an object, where the keys are `id`s of the inputs in the `PostOptionsStage`, and the values are the values that the user provided for each input.

  ```js Example (Jira) theme={null}
  await paragon.installFlow.setPostOptions({
    "JIRA_CLOUD_ID": "my-jira-cloud-id"
  });
  ```
</ParamField>

### <span id="installflowcancel">installFlow\.cancel()</span>

Call `installFlow.cancel()` if your user abandons the integration connection process during an active install flow. This function resets the state for `installFlow` to begin again at another time.

<Info>
  If your user has completed an OAuth connection but has *not* completed required post-OAuth options, this function will remove the credential with status `"PENDING"` automatically by calling `uninstallIntegration`.

  However, if the page has been refreshed or the SDK has been reloaded *since* the pending credential was connected, you will need to call `uninstallIntegration` manually to disconnect the pending credential from your user.
</Info>

### InstallFlowStage

These are the possible install flow stages received in the `onNext` callback of `InstallFlow` that should be rendered by your app to guide the user through the installation process.

<Tabs>
  <Tab title="AccountTypeStage">
    In the `AccountTypeStage`, the user should be prompted with a list of account types that they can choose from.

    If you want to skip this stage, pass the first account type option (or `"default"`) to `installFlow.setAccountType()` to move to the next stage.

    ```json Example (Salesforce) theme={null}
    {
      "stage": "accountType",
      "options": [
        { "id": "default", "accountDescription": "Production Account" },
        { "id": "sandbox", "accountDescription": "Sandbox Account"}
      ]
    }
    ```

    <ParamField path="stage" type="const">
      `"accountType"` for AccountTypeStage.
    </ParamField>

    <ParamField path="options" type="AccountType[]">
      The list of account types that the user can choose from.

      <Accordion title="Show child properties">
        <ParamField path="id" type="string" required>
          The ID of the account type. Pass this to `installFlow.setAccountType()` when the user selects an option.
        </ParamField>

        <ParamField path="accountDescription" type="string">
          The human-readable description of the account type.
        </ParamField>
      </Accordion>
    </ParamField>
  </Tab>

  <Tab title="PreOptionsStage">
    In the `PreOptionsStage`, the user should be prompted with inputs to collect the necessary details for API key authorization or for the next OAuth stage in the flow.

    ```json Example (Shopify) theme={null}
    {
      "stage": "preOptions",
      "options": [
        {
          "id": "SHOP_NAME",
          "title": "Enter your Shopify username",
          "subtitle": "Enter your Shopify username, e.g. https://<username>.myshopify.com.",
          "placeholder": "username",
          "type": "TEXT_NO_VARS"
        }
      ]
    }
    ```

    <ParamField path="stage" type="const">
      `"preOptions"` for PreOptionsStage.
    </ParamField>

    <ParamField path="options" type="InputType[]">
      The list of inputs to prompt the user with in this stage. You can see a full list of input types that are used by the Connect Portal and must be rendered by your implementation in [Input Types Reference](/connect-portal/input-types-reference).

      <Accordion title="Show child properties">
        <ParamField path="id" type="string" required>
          Use the input `id` as the key of the object you pass to [`setPreOptions()`](#setpreoptions). The value will be the input provided by the user.
        </ParamField>

        <ParamField path="type" type="enum" required>
          The type of this input, which will be one of the inputs in [Input Types Reference](/connect-portal/input-types-reference).
        </ParamField>

        <ParamField path="title" type="string" required>
          The title to display to the user to describe this input.
        </ParamField>

        <ParamField path="subtitle" type="string">
          The descriptive text to display to the user to further describe or provide context to this input.
        </ParamField>

        <ParamField path="placeholder" type="string">
          The placeholder or example value to display to the user.
        </ParamField>
      </Accordion>
    </ParamField>
  </Tab>

  <Tab title="PostOptionsStage">
    In the `PostOptionsStage`, the user should be prompted with inputs to finalize their account setup after the OAuth flow.

    ```json Example (Jira) theme={null}
    {
      "stage": "postOptions",
      "options": [
        {
          "id": "JIRA_CLOUD_ID",
          "type": "DYNAMIC_ENUM",
          "title": "Choose a Jira site to connect.",
          "subtitle": "The Jira site, where all operations will be performed.",
          "sourceType": "getAvailableSites",
          "required": true
        }
      ],
      "done": false
    }
    ```

    <ParamField path="stage" type="const">
      `"postOptions"` for PostOptionsStage.
    </ParamField>

    <ParamField path="options" type="InputType[]">
      The list of inputs to prompt the user with in this stage. You can see a full list of input types that are used by the Connect Portal and must be rendered by your implementation in [Input Types Reference](/connect-portal/input-types-reference).

      <Accordion title="Show child properties">
        <ParamField path="id" type="string" required>
          Use the input `id` as the key of the object you pass to [`setPostOptions()`](#setpostoptions). The value will be the input provided by the user.
        </ParamField>

        <ParamField path="type" type="enum" required>
          The type of this input, which will be one of the inputs in [Input Types Reference](/connect-portal/input-types-reference).
        </ParamField>

        <ParamField path="title" type="string" required>
          The title to display to the user to describe this input.
        </ParamField>

        <ParamField path="subtitle" type="string">
          The descriptive text to display to the user to further describe or provide context to this input.
        </ParamField>

        <ParamField path="placeholder" type="string">
          The placeholder or example value to display to the user.
        </ParamField>

        <ParamField path="sourceType" type="string">
          The source type of this input, defined for dynamic enum inputs. This value can be passed to [`getFieldOptions`](#getfieldoptions) to load the options for the input.

          See a walkthrough of implementing dynamic input types in [Exposing User Settings](/connect-portal/headless-connect-portal#exposing-user-settings).
        </ParamField>

        <ParamField path="required" type="boolean">
          Whether this input is required.
        </ParamField>
      </Accordion>
    </ParamField>
  </Tab>

  <Tab title="InstructionStage">
    In the `InstructionStage`, the user should be shown instructional content with call-to-action buttons and a finish button to proceed to the next stage.

    ```json Example (Salesforce) theme={null}
    {
      "stage": "instruction",
      "content": "## Install Package\n\nPlease install the package using the link below.\n\n![Install Image](https://cdn.useparagon.com/image.png \"Install Image\")\n\nAfter installation, click the finish button.",
      "ctas": [
        {
          "type": "link",
          "label": "Install Package",
          "href": "https://example.com/package-install"
        },
        {
          "type": "copyButton",
          "label": "Copy link",
          "copyText": "https://example.com/package-install"
        }
      ],
      "finish": {
        "type": "finishButton",
        "label": "I've installed the package",
        "onClick": Function
      },
      "done": false
    }
    ```

    <ParamField path="stage" type="const">
      `"instruction"` for InstructionStage.
    </ParamField>

    <ParamField path="content" type="string" required>
      Markdown-formatted content to display to the user. This can include headings, images, and other markdown elements.
    </ParamField>

    <ParamField path="ctas" type="CTA[]">
      An array of call-to-action buttons to display alongside the content. Each CTA can be either a link or a copy button.

      <Accordion title="Show child properties">
        <Tabs>
          <Tab title="Link">
            <ParamField path="type" type="const" required>
              `"link"` for Link CTAs.
            </ParamField>

            <ParamField path="label" type="string" required>
              The text to display on the link button.
            </ParamField>

            <ParamField path="href" type="string" required>
              The URL to navigate to when the link is clicked.
            </ParamField>
          </Tab>

          <Tab title="CopyButton">
            <ParamField path="type" type="const" required>
              `"copyButton"` for CopyButton CTAs.
            </ParamField>

            <ParamField path="label" type="string" required>
              The text to display on the copy button.
            </ParamField>

            <ParamField path="copyText" type="string" required>
              The text to copy to the clipboard when the button is clicked.
            </ParamField>
          </Tab>
        </Tabs>
      </Accordion>
    </ParamField>

    <ParamField path="finish" type="FinishButton" required>
      The finish button that the user clicks to proceed to the next stage after completing the instructions.

      <Accordion title="Show child properties">
        <ParamField path="type" type="const" required>
          `"finishButton"` for FinishButton.
        </ParamField>

        <ParamField path="label" type="string" required>
          The text to display on the finish button.
        </ParamField>

        <ParamField path="onClick" type="function" required>
          The callback function provided by the SDK to execute when the finish button is clicked. When this button is clicked, call `finish.onClick()` to mark the instruction stage as complete.
        </ParamField>
      </Accordion>
    </ParamField>
  </Tab>
</Tabs>

## ExternalFilePicker

You can use the Paragon SDK to allow your user to select files from a File Storage integration in your app.

The SDK provides an `ExternalFilePicker` class to load any necessary JavaScript dependencies into your page and authenticate with your user's connected account.

#### Supported integrations for ExternalFilePicker

* [Google Drive](/resources/integrations/google-drive#using-the-google-drive-file-picker)
* [OneDrive](/resources/integrations/onedrive#using-the-onedrive-file-picker)
* [SharePoint](/resources/integrations/sharepoint#using-the-sharepoint-file-picker)
* [Box](/resources/integrations/box#using-the-box-file-picker)

### new paragon.ExternalFilePicker(integrationType, options)

Construct a new instance of an ExternalFilePicker for an integration given by `integrationType`. Any required JS dependencies do not start loading until [`.init`](/apis/api-reference#picker-init-initconfig) is called.

**Example:**

```javascript theme={null}
const picker = new paragon.ExternalFilePicker("googledrive", {
  allowedTypes: ["application/pdf"],
  allowMultiSelect: false,
  onFileSelect(files) {
    console.log("User picked files", files);
  },
});
```

#### Options

* `allowedTypes` (default: `undefined`)
  * An array of MIME types to allow for file selection, e.g. `["application/pdf", "image/jpeg"]`

  * If `undefined`, all types will be allowed.

* `allowMultiSelect` (default: `false`)
  * If `true`, allow multiple files to be selected.

* `allowFolderSelect` (default: `false`)
  * If `true`, allow folders to be selected.

* `onOpen()`
  * Called when a Picker successfully appears in the app.

* `onClose()`
  * Called when a Picker gets closed.

* `onFileSelect(files)`
  * Called when a Picker file selection is made.

  * `files` is an Array of objects with the selected file objects from the 3rd-party picker script.

* `onCancel()`
  * Called when a Picker gets closed without any files selected.

### picker.init(initConfig)

Initialize a file picker with required configuration `initConfig`. Required configuration varies per integration; see [integration-specific documentation](/apis/api-reference#supported-integrations-for-externalfilepicker) for specific details.

This function loads required JS dependencies into the page, if they have not already been loaded. Other methods, like `.open` and `.getInstance`, cannot be called until the Promise returned by `.init` is resolved.

**Example:**

```js theme={null}
await picker.init({
  // Google Developer Key
  developerKey: "AIzaS...",
});
```

`initConfig` also accepts `selectedCredentialId`, which can be passed to select a specific account to pick files from when using [Multi-Account Authorization](/apis/api-reference/multi-account-authorization).

### picker.open()

Presents the file picker in your app.

Selected files or other events will be received in the [callbacks](/apis/api-reference#options) you specified in the constructor.

**Example:**

```js theme={null}
picker.open();
```

### picker.getInstance()

Returns a reference to the third-party JS library object that this file picker is using. This object can be used for additional integration-specific customization.
