# List connectors

> Source: https://elaichi.ai/docs/api-reference/connectors/connector/listconnectors/

`GET /connector`

Resource: **Connector** · API: **Connectors**

## Query parameters

- **`search`** _(string)_
  Substring match on the connector name/label.
- **`category`** _(string)_
  Exact category match.
- **`custom`** _(boolean)_
  Send `true` to narrow to this organization's own connectors.

## Response body

- **`result`** _(array<object>)_
  - **`slug`** _(string)_
    Stable connector key — this is the identifier everywhere, not an id.
  - **`label`** _(string)_
  - **`category`** _(string)_
  - **`logo`** _(string,null)_
  - **`description`** _(string,null)_
  - **`owner`** _(string)_
    Catalog owner. Org-owned values mark this org's custom connectors. Always this string — the owning MEMBER is `owner_member`, a separate field, so a client never has to tell a string from an object.
  - **`owner_member`** _(object | null)_
    The resolved owning member, the same shape as a toolbox's `owner`. Org-owned rows the caller reaches (ownership or a grant) only: an object when somebody OTHER than the caller owns the connector (just `{ id }` for an owner who has left the org); `null` when the connector has no owner yet (an ownerless connector — see `POST /connector/{slug}/owner`); absent when the caller owns it (`owner_user_id` already says so) or reaches it by nothing but `connector:view`. Names come from one batched lookup per page.
    _One of:_
    - **object**
      - **`id`** _(string)_
        User id (`usr_…`) — same value as `owner_user_id`.
      - **`name`** _(string,null)_
      - **`email`** _(string)_
      - **`avatar_url`** _(string,null)_
        The person's picture — the same one the console's user menu draws: their stored profile picture, else a Gravatar URL (`d=404`, 96px) derived server-side from their email (the address itself is not sent), else null. Draw initials when it is null or the image fails to load.
  - **`custom`** _(boolean)_
    True for a connector this organization authored or forked.
  - **`kind`** _(string)_
    `remote_mcp` for an organization's own bring-your-own remote MCP connector (its tools are discovered per connection, not read from the catalog), `catalog` for every other connector. Read it instead of guessing from the slug. On the detail, a remote MCP connector also carries `remote_mcp` (`url`, `auth_mode`, `oauth_registration`, `catalog_owner`, `listed_tool_count` — the server's count of the rows `GET /connector/{slug}/tool` lists to this caller with no filter, turned-off tools included for a caller who can manage the connector — and `support_contact`, the email or https link staff entered for a connector Elaichi publishes, null otherwise) and `auth`; its `tool_count` is the server's count of the tools that are switched on.
    Allowed: `catalog`, `remote_mcp`
  - **`byoa`** _(boolean)_
    True when the connector needs a customer OAuth app (BYOA) — a placeholder client id, a real id with a placeholder secret, or a real id with no platform OAuth secret stored for it. The first two are derived from the config on the catalog summary, so they are on every row; the third comes from one cached platform-credential read.
  - **`single_redirect_auth`** _(boolean)_
    A hint, not a promise: true when connecting this connector is most likely a provider sign-in with nothing to fill in first — exactly one auth method, and that method can redirect (OAuth). A list row judges the auth methods only; `GET /connector/{slug}` also rules out a method with form fields or a `permissions_text` notice. A client may use it to get a popup window ready inside the click that starts a connect. `direct_connect_url` on the `POST /connection` / reconnect response stays authoritative.
  - **`can_fork`** _(boolean)_
    Whether THIS caller may fork the connector, computed server-side so a client never re-derives it: false for a remote MCP connector (`POST /connector/{slug}/fork` answers `409 connector_not_forkable`), for a connector the caller is restricted from, without `connector:create`, and when the plan does not include custom connectors. On `GET /connector` rows and `GET /connector/{slug}`.
  - **`owner_user_id`** _(string)_
    Owning member (`usr_…`), from the connector's `connector_owner` row. Present only on an org-owned row the caller reaches (ownership or a grant) AND that has an owner — an ownerless connector has none until `POST /connector/{slug}/owner` (or the creator backfill) assigns one, and a member browsing on `connector:view` alone is not told whose it is — such a connector is not shown to them at all (org owners/admins included). The owner is implicit `edit`, plus delete and transfer — the two things no share confers.
  - **`can_use`** _(boolean)_
    Whether the caller may create (or re-authenticate) a connection from this connector — the `use` floor `POST /connection` and `POST /connection/{id}/reconnect` enforce, which answers 403 `connector_not_shared` when it is not met. For an org-owned connector: ownership or a `use`-or-better grant (direct, team or org-wide). Always true on a platform catalog row, which has no ACL. This is the SHARING answer, independent of `restricted`: a connector shared for viewing only is listed but not connectable, and a client should leave Connect off rather than show a button that refuses. A connector nobody shared with the caller at all is not listed.
  - **`can_manage`** _(boolean)_
    Present only on org-owned/custom connector rows (omitted for platform catalog rows, which have no ACL concept). Whether the caller may edit this connector's config — ownership or a real `edit` grant of their own. `connector:manage` alone no longer implies this (removed 2026-09-04): org owners/admins do not manage-by-default a connector nobody explicitly shared with them.
  - **`can_transfer`** _(boolean)_
    Org-owned rows only. Whether the caller may transfer this connector — ownership, full stop; no `connector:manage` fallback. Mirrors `POST /connector/{slug}/transfer`. False for everyone on an ownerless connector (transfer needs an owner). Not the delete gate — see `can_delete`.
  - **`can_delete`** _(boolean)_
    Org-owned rows only. Whether the caller may delete this connector: the owner, and only the owner, so false for everyone on an ownerless connector. Currently the same formula as `can_transfer`, kept as its own field so a client gates Delete on the delete question. Mirrors `DELETE /connector/{slug}`; the console gates its Delete on this.
  - **`can_assign_owner`** _(boolean)_
    Org-owned rows only. Whether the caller may give this ownerless connector an owner: it has no owner row AND the caller holds `connector:manage`. Mirrors `POST /connector/{slug}/owner` naming another member. Independent of the caller's reach, so a manager browsing the catalog can see that a connector needs an owner; it says nothing about who has access.
  - **`can_claim`** _(boolean)_
    Org-owned rows only. Whether the caller may make THEMSELVES the owner: `can_assign_owner` AND a real `edit` grant of their own. `connector:manage` alone never makes its holder the owner of a connector nobody shared with them. Mirrors `POST /connector/{slug}/owner` naming the caller.
  - **`can_revoke_share`** _(boolean)_
    Org-owned rows only. `can_share`'s formula — edit access or ownership AND `connector:share` — a THIRD formula, distinct from `can_manage`: an `edit` grantee whose role omits `connector:share` can reconfigure the connector but was never meant to grant or revoke someone else's access. Mirrors `DELETE /connector/{slug}/share/{aclId}`.
  - **`restricted`** _(boolean)_
    True when the caller's restrictions block this whole connector. A blocked connector is LISTED and flagged, never omitted — a picker that only got "no match" could not tell "your admin blocked it" from "that provider does not exist". It still cannot be connected: `POST /connection` and `GET /connector/{slug}/tools` refuse it.
  - **`restricted_by`** _(string,null)_
    Which precedence layer the winning rule came from, or null when nothing blocks this connector. Adds *which* to `restricted`'s *whether* and nothing else — no rule id, author, reason or coverage. Same field and same meaning as on `GET /connector/{slug}` and on a connection row.
    Allowed: `role`, `user`, `null`
  - **`restricted_inherited_from`** _(object,null, required)_
    Set when this connector is restricted for the caller ONLY because the connector it was forked from is — a fork inherits its upstream's restrictions on purpose (forking a blocked connector is not a bypass), but nothing was set on the fork itself, so this says where the block came from. Null when not restricted, when a rule names this connector directly, or when the lineage could not be walked. Asking for access still targets THIS connector: approving the fork's own request lifts the inherited block for that fork only. Sibling of `restricted_by` (which stays the precedence layer); computed server-side in the same batch as the restriction evaluation — clients must not derive it from lineage.
  - **`access_via`** _(string)_
    How the CALLER reaches this connector — not who else can. `owner` — they own it. `direct` — a grant naming them personally. `team` — a grant to a team they belong to (or, per §6.2, one they administer), named in `access_via_team`. `org` — an organization-wide grant. When several sources apply the BROADEST wins and the caller's access level is not consulted: owner, else `org`, else `team`, else `direct`. So a caller granted `edit` personally AND `view` org-wide reads `org` — a narrower grant must never mask org-wide exposure, since this field says how far the connector reaches, not what the caller may do with it. Deliberately NOT gated on `can_see_shares`, and deliberately not a widening of it: this is the caller's OWN grant and their OWN team memberships, so a `view`/`use` grantee receives it while the grantee list — information about colleagues — stays closed to them. No other member is ever named. ABSENT when nothing reaches the caller — a transfer answering the ex-owner of a resource that was never shared, or a catalog row browsed with no grant behind it. Absent means "no source to name", never "not permitted", and never an implied `org`.
    Allowed: `owner`, `direct`, `team`, `org`
  - **`access_via_team`** _(object)_
    Present exactly when `access_via` is `team`, absent otherwise. The team the caller reaches this connector through — one of their own teams, never a disclosure about anybody else.
    - **`id`** _(string)_
      Team id (`team_…`).
    - **`name`** _(string,null)_
      Team display name, or null when the team no longer resolves in the directory — the same null contract every resolved grantee name carries.
- **`next_cursor`** _(string,null)_
- **`prev_cursor`** _(string,null)_

## Code examples

### curl

```bash
curl -X GET 'https://api.elaichi.ai/connector' \
  -H 'Authorization: Bearer $ELAICHI_API_TOKEN' \
  -H 'Content-Type: application/json'
```

### JavaScript

```javascript
const response = await fetch('https://api.elaichi.ai/connector', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer ' + process.env.ELAICHI_API_TOKEN,
    'Content-Type': 'application/json',
  },
});

const data = await response.json();
console.log(data);
```

### Python

```python
import os
import requests

url = "https://api.elaichi.ai/connector"
headers = {
    "Authorization": f"Bearer {os.environ['ELAICHI_API_TOKEN']}",
    "Content-Type": "application/json",
}

response = requests.get(url, headers=headers)
print(response.json())
```
