Skip to content
GET /connection/{id}

Status is reconciled against the vault on read. Connections the caller cannot see answer 404, never 403 — including another member's private connection, which no organization permission reaches. Resolves docs/access-model.md §4 ONLY, with no opt-in of any kind: the caller owns the connection, or holds a grant on it (directly, through a team, or org-wide). No grant, no fallback, `404` — even for a holder of `connection:view`/`connection:manage`. There is no oversight read for connections; a `visibility` query parameter is not accepted. `can_share`, `can_manage` and `can_transfer` report whether the caller may share, edit or transfer/delete this connection, respectively — see the schema for each; none of the three has a `connection:manage` fallback any more (removed 2026-09-04) — ownership or a real grant are the only ways to reach them. `access_summary`, a bounded "who has access" rollup, is present only when `can_share` is true — page `GET /connection/{id}/share` for the grants themselves.

Path Parameters

idstring
required·

Connection id (conn_…).

Response Body

accessstring

The caller's relationship to this connection: owner, or a granted view/use/edit level. There is no oversight fallback for connections — this is never "oversight"; a connection the caller neither owns nor holds a grant on is not visible to them at all, whatever organization permission they hold.

access_summaryobject

Present only when can_share is true. Bounded by design — page GET /connection/{id}/share for the grants themselves.

org_levelstring,null
Possible values:
viewusenull
previewobject[]

At most 5 grantees, broadest first (org, then teams, then members), for a hover preview.

4 properties
grantee_idstring,null
grantee_typestring
Possible values:
userteamorg
levelstring
Possible values:
viewuse
namestring,null

Display name; null for org grants and for grantees no longer in the org.

team_countinteger
totalinteger

Every grant, the org-wide one included.

user_countinteger
access_viastring

How the CALLER reaches this connection — 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 connection 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.

Possible values:
ownerdirectteamorg
access_via_teamobject

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.

idstring

Team id (team_…).

namestring,null

Team display name, or null when the team no longer resolves in the directory — the same null contract every resolved grantee name carries.

can_manageboolean

Present on every list and detail row. Whether the caller may edit this connection's own settings — owner, or edit access. No connection:manage fallback. Computed server-side; same can_manage name used by toolbox and connector for the identical capability.

can_revoke_shareboolean

can_share, verbatim — a THIRD formula, deliberately not an alias for can_manage: an edit grantee whose role omits connection:share (Auditor, Guest, any custom role) can reconfigure or reconnect the connection but was never meant to grant or revoke someone else's access to it, so can_manage: true on that row must not imply this control too. Mirrors DELETE /connection/{id}/share/{aclId}'s own gate exactly. Present on every list and detail row.

can_shareboolean

Whether the caller may share this connection — owner, edit access, or a team admin on a team-granted one. No connection:manage fallback. Computed server-side (CLAUDE.md's API-first rule); the console reads this rather than re-deriving it from owner_user_id/permissions.

can_transferboolean

Present on every list and detail row. Whether the caller may transfer or delete this connection — owner, full stop. No connection:manage fallback. Deliberately narrower than can_manage: an edit grant lets someone use and reconfigure a connection, never give it away or destroy it.

connected_by_labelstring,null

Display name for connected_by_user_id, resolved server-side one batch per page (name, else email). Present on every branch that returns a connection, commands included. A null HERE beside a NON-null connected_by_user_id is a fact about the person, not a failed lookup: they have left the organization, and clients render "Former member" — the same word the GET /audit-log actor summary uses. Compare the two fields, never one alone: a null id means "not recorded", a null label means "departed".

connected_by_user_idstring,null

Who AUTHENTICATED this account (usr_…) — the member whose third-party credential the vault actually holds. Written once at creation and never rewritten. Distinct from owner_user_id on purpose: POST /connection/{id}/transfer moves the owner and deliberately does NOT touch the vault account, so after a transfer these are two different people and only this one may be rendered as "Connected by". Null means NOT RECORDED, never "nobody" — every connection created before this field existed is null, because nothing server-side could tell a never-transferred row (where owner_user_id would have been the honest answer) from a transferred one, and a fabricated attribution is worse than an absent one. Render nothing for a null.

connector_slugstring

Which connector this account is on.

created_atstring · date-time
idstring

Connection id (conn_…).

last_errorstring,null
namestring
ownerobject,null

Owner summary. Currently never populated on a connection response — no list route resolves it today — but kept in the schema in case a future route does; read owner_user_id plus a member lookup instead.

emailstring · email
idstring

User id (usr_…) — same value as owner_user_id.

namestring,null
owner_user_idstring

Owning member (usr_…); calls run as this identity. Owner is implicit edit, plus delete and transfer — the two things 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.

saffron_account_idstring,null

Vault account holding the credential. Null until the connect flow completes.

sharesobject[]

Present only when the caller may see the ACL: owner or edit access. A view/use recipient is never told who else the connection is shared with. Absent (not empty) when the caller may not see it.

created_atstring · date-time
grantee_idstring,null

User id (usr_…) or team id (team_…). Null for a grantee_type: "org" grant.

grantee_typestring

user and team grants target one grantee_id; org applies to every member of the organization and takes no id.

Possible values:
userteamorg
idstring

ACL entry id — the :aclId a DELETE .../share/{aclId} call takes.

levelstring

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.

Possible values:
viewuseedit
resource_idstring

The shared resource's id (a connector's slug, for that type).

resource_typestring
Possible values:
connectiontoolboxtemplateconnector
updated_atstring · date-time
statusstring

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 lazily against the vault when connections are read.

Possible values:
pendingactiveneeds_reauthdisconnected
updated_atstring · date-time
curl -X GET 'https://api.elaichi.ai/connection/<id>' \
  -H 'Authorization: Bearer $ELAICHI_API_TOKEN' \
  -H 'Content-Type: application/json'
const response = await fetch('https://api.elaichi.ai/connection/<id>', {
  method: 'GET',
  headers: {
    'Authorization': 'Bearer ' + process.env.ELAICHI_API_TOKEN,
    'Content-Type': 'application/json',
  },
});

const data = await response.json();
console.log(data);
import os
import requests

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

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