---
title: "List connections"
method: GET
path: "/connection"
tags: ["Connections"]
---

# List connections

`GET /connection`

## Request

- Base URL: `https://api.elaichi.ai`
- URL: `https://api.elaichi.ai/connection`
- Auth: HTTP bearer

Lists the connections the caller owns plus every connection shared with them, directly, through a team they belong to, or organization-wide. No organization permission widens this: a private connection (no grants) appears only for its owner, whatever permission an org owner or admin holds, and there is no org-wide listing of connections. Statuses are refreshed as they are read, so this is also how a `needs_reauth` connection surfaces. A `pending` row whose sign-in finished but whose redirect never came back is bound shortly after the response, so it may still read `pending` and show as bound one load later. Rows the caller may share (owner or `edit` access) also carry `can_share: true` and a short `access_summary`; page `GET /connection/{id}/share` for the grants themselves.

## Query parameters

- `limit` integer
- `cursor` string
- `q` string
- `status` 'pending' | 'active' | 'needs_reauth' | 'disconnected'
- `connector_slug` string[]
- `owner_user_id` string

## Headers

- `X-Organization-Id` string

## Response `200`

OK

- object
  - `result` object[], required
    - `id` string: Connection id (`conn_…`).
    - `restricted_inherited_from` object, nullable: 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 upstream could not be traced. Asking for access still targets this connector: approving the fork’s own request opens that fork for that person only (whether the block comes through their role or a rule written about them personally) and the original stays restricted for them; the approved request reads `restriction_lifted: true`. A sibling of `restricted_by`, which stays the precedence layer. Do not derive it yourself from the fork’s upstream.
      - `slug` string, nullable, required: The upstream connector the restriction is inherited from. For API consumers; never render it. Null — together with `label` — when the caller may not be told the upstream (an org-owned upstream they hold no grant on, or one that was deleted): a slug names the connector as surely as its label does.
      - `label` string, nullable, required: The upstream's display name — null, together with `slug`, when the caller may not be told it. The UI then says "a connector this was forked from".
    - `connector_slug` string: Which connector this account is on.
    - `name` string
    - `owner_user_id` string: Owning member (`usr_…`); calls run as this identity. The owner has implicit `edit`, plus delete and transfer, which no share confers. Move it with `POST /connection/{id}/transfer`. This is who is accountable for the connection now, which after a transfer is not who authenticated it; see `connected_by_user_id`.
    - `connected_by_user_id` string, nullable: Who authenticated this account (`usr_…`): the member whose third-party credential Elaichi holds. Written once at creation and never rewritten. It differs from `owner_user_id` on purpose: `POST /connection/{id}/transfer` moves the owner and does not touch the stored credential, so after a transfer these are two different people and only this one should be shown as "Connected by". Null means not recorded, never "nobody": connections created before this field existed are null. Show nothing for a null.
    - `connected_by_label` string, nullable: Display name for `connected_by_user_id` (name, else email). Present on every response that returns a connection, commands included. A null label beside a non-null `connected_by_user_id` means the person has left the organization; show "Former member". Compare the two fields, never one alone: a null id means "not recorded", a null label means "departed".
    - `connector` object: The connector's display data, so a client needs no `GET /connector/{slug}` per distinct connector. On `GET /connection` rows and `GET /connection/{id}` (which adds `can_view_connector`, `available` and `auth_mode`, and always states `single_redirect_auth`); absent from the command responses, which cannot change a connection's connector.
      - `label` string, required: Catalog display name; the slug itself when the catalog cannot resolve it.
      - `logo` string, nullable, required: Logo URL; null when the connector has none.
      - `upstream_slug` string: Present only on a fork (an org-owned connector copied from another): the connector it was forked from. Omitted when the caller has no access to the fork or to a private upstream (naming it would disclose its slug), and when the upstream cannot be read.
      - `single_redirect_auth` boolean: The connector-row hint of the same name: connecting is most likely a single provider sign-in, so a client reserves a popup inside the Reconnect click. Always stated on `GET /connection/{id}` (false when `can_view_connector` is). On a list row it is stated only where the caller could open the connector, and ABSENT otherwise, which reads as unknown, never false.
      - `available` boolean: False only when the catalog no longer has the connector (Elaichi unpublished or deleted a platform connector): the connection is kept but nothing can work until it returns. On `GET /connection/{id}` it is `true` when the connector resolves; on a `GET /connection` row it is never `true`, only `false` or absent. Absent also when the catalog could not answer, so a brief outage never reads as an unpublished connector.
      - `auth_mode` 'oauth_auto' | 'oauth_client' | 'custom' | 'none': `GET /connection/{id}` only, remote MCP connectors only, and only when `can_view_connector`: how the connector signs in, so a screen can say "No sign-in" instead of "API key".
      - `can_view_connector` boolean: `GET /connection/{id}` only. Whether `GET /connector/{slug}` would answer this caller: false for a connector the catalog no longer resolves, without `connector:view`, and for an org-owned connector nobody shared with them (it 404s). Link to the connector only when true.
    - `saffron_account_id` string, nullable: Identifier of the stored credential Elaichi holds for this connection. Opaque; null until the connect flow completes.
    - `status` 'pending' | 'active' | 'needs_reauth' | 'disconnected': `pending` = created but not yet authenticated (open `connect_url`); `active` = usable; `needs_reauth` = the credential expired or was revoked upstream, call reconnect; `disconnected` = no longer usable. Refreshed when connections are read.
    - `last_error` string, nullable
    - `access` string: The caller's relationship to this connection: `owner`, or a granted `view`/`use`/`edit` level. A connection the caller neither owns nor holds a grant on is not visible to them at all, whatever organization permission they hold.
    - `owner` object: Who `owner_user_id` is. Present on a connection the caller does not own and absent on their own. On every response that returns a connection (list, detail and the command responses), so a transfer names the new owner without a reload. `name` and `email` are absent for an owner who has left the organization ("Former member").
      - `id` string, required: User id (`usr_…`) — same value as `owner_user_id`.
      - `name` string: Display name, else the email.
      - `email` string, email
      - `avatar_url` string, nullable: The person's picture: their stored profile picture, else a Gravatar URL (`d=404`, 96px) derived from their email (the address itself is not sent), else null. Draw initials when it is null or the image fails to load.
    - `shares` AclEntry[]: Present only when the caller may see who the connection is shared with: the owner or `edit` access. A `view` or `use` recipient is never told who else it is shared with. Absent (not empty) when the caller may not see it.
      - `id` string: Grant id (`acl_…`), the `{aclId}` that `DELETE .../share/{aclId}` takes.
      - `resource_type` 'connection' | 'toolbox' | 'template' | 'connector' | 'file'
      - `resource_id` string: The shared resource's id (a connector's slug, for that type).
      - `grantee_type` 'user' | 'team' | 'org': `user` and `team` grants target one `grantee_id`; `org` applies to every member of the organization and takes no id.
      - `grantee_id` string, nullable: User id (`usr_…`) or team id (`team_…`). Null for a `grantee_type: "org"` grant.
      - `level` 'view' | 'use' | 'edit': Same ladder for every shareable resource, low to high. `view` — see it exists, read its metadata/config; cannot exercise it. `use` — `view` + exercise it, resource-specific: run tools through a connection; execute a toolbox's tools through its bound connections (this DELEGATES — the caller runs through each entry's pinning editor's own authority, not necessarily their own); stamp a new toolbox by copying a template's entries; create connections from a connector. `edit` — `use` + change its settings, entries and its own grants.
      - `created_at` string, date-time
      - `updated_at` string, date-time
    - `created_at` string, date-time
    - `updated_at` string, date-time
    - `can_share` boolean: Whether the caller may share this connection: the owner, `edit` access, or a team admin on a team-granted one, and `connection:share`. Computed by the API, so read it rather than re-deriving it from `owner_user_id` and permissions.
    - `can_manage` boolean: Present on every list and detail row. Whether the caller may edit this connection's own settings: the owner, or `edit` access.
    - `can_transfer` boolean: Present on every list and detail row. Whether the caller may transfer or delete this connection: the owner only. Narrower than `can_manage`, because an `edit` grant lets someone use and reconfigure a connection, never give it away or destroy it.
    - `can_revoke_share` boolean: Present on every list and detail row. Whether the caller may grant or revoke access to this connection. It matches `can_share` and is separate from `can_manage`: an `edit` grantee whose role omits `connection:share` can reconfigure or reconnect the connection but cannot change who else has access. Mirrors `DELETE /connection/{id}/share/{aclId}`.
    - `access_summary` object: Present only when `can_share` is true. A short summary of who has access; page `GET /connection/{id}/share` for the grants themselves.
      - `org_level` 'view' | 'use' | 'null', nullable
      - `team_count` integer
      - `user_count` integer
      - `total` integer: Every grant, the org-wide one included.
      - `preview` object[]: At most 5 grantees, broadest first (org, then teams, then members), for a hover preview.
        - `grantee_type` 'user' | 'team' | 'org'
        - `grantee_id` string, nullable
        - `level` 'view' | 'use'
        - `name` string, nullable: Display name; null for org grants and for grantees no longer in the org.
    - `access_via` 'owner' | 'direct' | 'team' | 'org': How the caller reaches this connection, not who else can. `owner`: they own it. `direct`: a grant names them personally. `team`: a grant to a team they belong to (or administer), named in `access_via_team`. `org`: an organization-wide grant. When several sources apply, the broadest wins and the access level plays no part: owner, else `org`, else `team`, else `direct`. A caller with `edit` personally and `view` org-wide reads `org`, because this field says how far the connection reaches, not what the caller may do with it. It describes only the caller's own access, so a `view` or `use` grantee still gets it while the list of other grantees stays hidden. Absent when nothing reaches the caller (for example, the former owner after a transfer of a resource that was never shared); absent never means `org`.
    - `access_via_team` object: Present exactly when `access_via` is `team`, absent otherwise. The team the caller reaches this connection through — one of their own teams, never a disclosure about anybody else.
      - `id` string: Team id (`team_…`).
      - `name` string, nullable: 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, nullable, required
  - `prev_cursor` string, nullable, required

## Other responses

- `400`: Bad request
- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not found
- `429`: Rate limited

---

[API](https://skmtc.dev/elaichi/apis/elaichi-api.md) · [All operations](https://skmtc.dev/elaichi/apis/elaichi-api/llms.txt) · [OpenAPI document](https://skmtc.dev/elaichi/apis/elaichi-api/revisions/b22cfb7b6d15?raw)
