> Source: https://wexa.ai/docs/connectors/configure-connector

# configure-connector

Provision a connector that needs credentials (an API key, a password or OAuth) in this project, or change one, the same as the console's create page. Needs the `fabric:skill.write` grant, and a project or organization admin.

**Configure a connector**

**Wexa MCP server**

```bash
curl -sS -X POST https://fabric.wexa.ai/mcp/$FABRIC_PROJECT_ID \
  -H "authorization: Bearer $FABRIC_API_KEY" \
  -H "Mcp-Session-Id: $MCP_SESSION_ID" \
  -H "content-type: application/json" -H "accept: application/json" \
  -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"configure-connector","arguments":{"category":"servicenow","name":"ServiceNow","credentials":{"instance_url":"<instance-url>","username":"<username>","password":"<password>"},"access_scope":"organization"}}}'
```

```json
{
  "content": [
    {
      "type": "text",
      "text": "{\"lifecycle_id\":\"qlc_000014\",\"result\":{\"connector_id\":\"6b1a3d5e7f9c0b2a4d6e8f01\",\"status\":\"ready\"}}"
    }
  ],
  "isError": false
}
```

**REST API**

```bash
curl -sS https://fabric.wexa.ai/v1/configure-connector \
  -H "authorization: Bearer $FABRIC_API_KEY" \
  -H "content-type: application/json" \
  -d '{"category":"servicenow","name":"ServiceNow","credentials":{"instance_url":"<instance-url>","username":"<username>","password":"<password>"},"access_scope":"organization"}'
```

```json
{
  "lifecycle_id": "qlc_000014",
  "result": {
    "connector_id": "6b1a3d5e7f9c0b2a4d6e8f01",
    "status": "ready"
  }
}
```

**TypeScript SDK**

```ts
import { Fabric } from '@wexa-fabric/sdk'

const fabric = new Fabric()
const result = await fabric.configureConnector({
  category: 'servicenow',
  name: 'ServiceNow',
  credentials: {
    instance_url: '<instance-url>',
    username: '<username>',
    password: '<password>'
  },
  access_scope: 'organization'
})
```

```ts
// result is the payload itself, with no `.result` to read
{
  connector_id: '6b1a3d5e7f9c0b2a4d6e8f01',
  status: 'ready'
}
```

**Python SDK**

```python
from wexa import Fabric

fabric = Fabric()
out = fabric.configure_connector(
    category="servicenow",
    name="ServiceNow",
    credentials={
        "instance_url": "<instance-url>",
        "username": "<username>",
        "password": "<password>"
    },
    access_scope="organization",
)
```

```python
# out is the result, already unwrapped
{
    "connector_id": "6b1a3d5e7f9c0b2a4d6e8f01",
    "status": "ready"
}
```

## Parameters

| Parameter | Type | Required | Notes |
| --- | --- | --- | --- |
| `category` | string | Required | The connector category, such as `servicenow`. Case does not matter. For a data source, its service type in lower case (`snowflake`). Non-empty. |
| `name` | string | Required | The connector's name in this project. Non-empty. |
| `credentials` | object | Optional | Setup form values by field id, from [`get-connector-form`](/docs/connectors/get-connector-form). Integers as numbers. Must be an object. |
| `om_connection` | object | Optional | For a data source from [`list-om-catalog`](/docs/connectors/list-om-catalog), instead of `credentials`: values from [`get-om-connection-form`](/docs/connectors/get-om-connection-form). Not empty, and not with `credentials` or `connector_id`. A category not in `list-om-catalog` is refused. |
| `filters` | object | Optional | With `om_connection` only: what to catalogue, by filter field id such as `databaseFilterPattern`, each `{"includes": [...], "excludes": [...]}`. Leave out to include everything. Malformed, or without `om_connection`, is refused. |
| `access_scope` | string | Optional | Who may use the connector, from [`list-connector-access-scopes`](/docs/connectors/list-connector-access-scopes). |
| `connector_id` | string | Optional | Change this connector instead of provisioning another. Only what you pass is sent. Not for a data source. |
| `return_to` | string | Optional | Where the provider's sign-in sends the person back. Must be an `https://` URL. |

**Errors**

- `ForbiddenError` (403): you are not an admin.
- `PolicyDenied` (403): a policy would have held the call for approval.
- `ValidationError` (400): the platform refused the values, with its reason.
- `NotFound` (404): the platform found nothing to configure.
- `ConflictError` (409): the change collides with the platform's current state.

**Show full response**

- `connector_id`: the connector this call created, or the one it changed. Pass it to the other connector tools.
- `status`: the connector's status, as the platform gives it. When the platform gives none: `awaiting_authentication` when it asks for a further step, otherwise `ready`.
- `auth_url`: present only when the provider signs the person in, the `https://` page to open next.

An example response, for a new ServiceNow connector whose provider does not sign the person in.

**Result of configure-connector**

**REST API**

```json
{
  "lifecycle_id": "qlc_000014",
  "result": {
    "connector_id": "6b1a3d5e7f9c0b2a4d6e8f01",
    "status": "ready"
  }
}
```

**Wexa MCP server**

```json
{
  "content": [
    {
      "type": "text",
      "text": "{\"lifecycle_id\":\"qlc_000014\",\"result\":{\"connector_id\":\"6b1a3d5e7f9c0b2a4d6e8f01\",\"status\":\"ready\"}}"
    }
  ],
  "isError": false
}
```

**TypeScript SDK**

```ts
// the object you get back IS the result — there is no `.result` to read
{
  "connector_id": "6b1a3d5e7f9c0b2a4d6e8f01",
  "status": "ready"
}

// The TS SDK names these camelCase — lifecycleId, traceId — where Python uses
// lifecycle_id and trace_id. Both are non-enumerable: readable, but omitted by
// Object.keys() and JSON.stringify(). `result.lifecycleId` here is undefined.
result.lifecycleId // 'qlc_000014'
```

**Python SDK**

```python
# a dict subclass; `result` is already unwrapped
{
 "connector_id": "6b1a3d5e7f9c0b2a4d6e8f01",
 "status": "ready"
}

out.lifecycle_id  # 'qlc_000014' — an attribute, not a key
```

For a provider that signs the person in, the answer also carries `auth_url`, the page to open to finish connecting.

**More details**

The `PolicyDenied` message names the policy's reason and says to configure the connector in the console instead. Every password, key and token in `om_connection` is masked like `credentials`. Changing a connector with `connector_id` sends only what you pass, so it keeps its triggers, tags and schedule. A data source's connection cannot be changed with `connector_id`: delete the connector and provision it again. The error codes are `S8:connector-admin-only` (not an admin), `S5:policy` (a policy would have held it) and `S4:validate-input` (the arguments). Dotted `om_connection` ids such as `authType.password` may be passed as they are or nested. Credential values the platform's refusal quotes are masked. The platform's own reason is the message on `NotFound`, `ConflictError` and the 400 `ValidationError`.

The field ids under `credentials` in the example are illustrative: take the real ones from `get-connector-form` for your category. A value in angle brackets is one only you can supply, and the platform refuses a literal `<...>`.

To provision one, pass the `category`, a `name` and `credentials`. Wexa starts from the category's template, fills in your values and saves the connector. The platform validates the values and keeps the secrets in its vault. Some providers sign the person in after the connector is saved. For those, the answer carries `auth_url`: open it to finish.

To connect a data source such as Snowflake, pass `om_connection` instead of `credentials`. Wexa sends the same body the console's Data Sources wizard does, with no template read first. A connector that needs no credentials is connected with [`provision-connector`](/docs/connectors/provision-connector) instead, and a WhatsApp account with [`connect-whatsapp`](/docs/connectors/connect-whatsapp).

The credentials are never logged, stored or returned. The call is never held for approval, because an approval request would store its arguments: a policy that would hold it refuses it instead, with `PolicyDenied`, and writes nothing to the approvals store. The `credentials` argument is masked wherever Wexa records the call's arguments. When the platform's refusal quotes a value you sent, Wexa replaces the value with `•••` before the error reaches you. The answer carries only `connector_id`, `status` and `auth_url`, never the saved configuration. Do not log the credentials in your own code either.

Every call that tries to save the connector writes a `configure-connector.run` audit event, with the category, the connector, the access scope, the ids of the fields that were set, and the outcome: `configured` or `failed`. It records which fields were set, never their values. A failed call records the error, with any credential value in it masked. A call refused before the save, for example by the admin check, writes no such event.

Not marked consequential, for the same reason it is never held: an approval would store the credentials. So the project's write gate does not apply to it. What protects it instead is that only an admin may call it, as in the console.

See also [`list-connector-catalog`](/docs/connectors/list-connector-catalog), [`delete-connector`](/docs/connectors/delete-connector) and [`list-connectors`](/docs/connectors/list-connectors).

Every tool call works the same way: [How every tool call works](/docs/sdks-and-apis/how-every-tool-call-works).
