# Get connector (/docs/reference/connectors/get)

`GET https://api.corespeed.io/connectors/:id`

Returns the same entry shape as the index, for one connector. This read adds
`tools` when the tool list is known: each tool's `name`, and its `description`
and `annotations` once the tool's provider has described it. Each account adds
two fields here. `grants` lists an account's shares (`grantee_id`,
`grantee_kind` of `"member"`, `"agent"`, or `"org"`, and `tools`, where `null`
means every tool); it appears only on accounts you may share. `granted_tools`
is on an account shared with you: the tools that share allows, or `null` for
every tool.

Org-registered remote MCP connectors are read at
**`GET /connectors/org/:slug`** instead — their own tree, so a remote slug
and a same-named built-in connector each answer on their own path. The remote
read additionally carries the verbatim snapshot tool list under
`remote.tools`.

Tied machines (`kind: "device"`) have no read here:
`GET /connectors/device__<slug>` answers `404 endpoint_not_found`. Their index
entry is the whole of a device on this API — see
[List connectors](/docs/reference/connectors/list).

#### Authorizations

* `Authorization` (string, header, required) — `Bearer <sk-cs-…>` — a CoreSpeed API key, or a user session JWT. `x-api-key: <sk-cs-…>` is accepted in its place.

#### Path parameters

* `id` (string, path, required) — The `id` of an index entry without a `kind` — an OAuth connector.

A connector that exists and is served here but has no connected account returns
`200` with `status: "disconnected"` and an empty `accounts` array — that is the
answer that tells you to send a user to the dashboard.

A `404` means **this endpoint has nothing to serve you for that id**, which
covers two cases you cannot tell apart and should not try to: the id does not
exist, or it exists but is not offered to you here (upstream approval still in
progress, credentials not present here, or not yet open to your
organization). Whether a connector is offered is internal operations state, so
it is not published on any endpoint — the responses are deliberately
identical.

Treat `GET /connectors` as the only source of truth for what you can connect:
an id absent from the index is not connectable here, whatever the reason.
Attempting a connect flow for one fails, so there is no state in which
probing this endpoint tells you something the index did not.

One exception, and it exists so a grant can always be revoked: if you still
have accounts on a connector that has since stopped being offered, this
endpoint keeps serving that entry (and `DELETE` keeps working on it). Without
it, a credential that outlived its environment's OAuth app would become an
orphan nobody could disconnect.

Failures use the nested `{ "error": { type, code, message } }` envelope,
like every other route; branch on `error.code`. Every code is in
[Errors & status codes](/docs/reference/errors).

**curl**

```bash
curl https://api.corespeed.io/connectors/notion \
  -H "Authorization: Bearer $CORESPEED_API_KEY"
```

**TypeScript**

```ts
const res = await fetch("https://api.corespeed.io/connectors/notion", {
  headers: { Authorization: `Bearer ${process.env.CORESPEED_API_KEY}` },
});

// 404 = nothing to serve for this id here: unknown, or not offered on this
// environment. Both mean "not connectable" — read GET /connectors for what is.
if (res.status === 404) throw new Error("connector not available here");
const connector = await res.json();
console.log(connector.status);
```

**Python**

```python
import os
import httpx

res = httpx.get(
    "https://api.corespeed.io/connectors/notion",
    headers={"Authorization": f"Bearer {os.environ['CORESPEED_API_KEY']}"},
)

# 404 = nothing to serve for this id here: unknown, or not offered on this
# environment. Both mean "not connectable" — read GET /connectors for what is.
if res.status_code == 404:
    raise RuntimeError("connector not available here")
print(res.json()["status"])
```

**Go**

```go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
)

func main() {
	req, _ := http.NewRequest("GET", "https://api.corespeed.io/connectors/notion", nil)
	req.Header.Set("Authorization", "Bearer "+os.Getenv("CORESPEED_API_KEY"))

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	// 404 = nothing to serve for this id here: unknown, or not offered on this
	// environment. Both mean "not connectable" — read GET /connectors for what is.
	if res.StatusCode == http.StatusNotFound {
		panic("connector not available here")
	}

	var connector struct {
		Status string `json:"status"`
	}
	json.NewDecoder(res.Body).Decode(&connector)
	fmt.Println(connector.Status)
}
```

**200 OK** — Exists but not connected

```json
{
  "id": "linear",
  "category": "projects",
  "name": "Linear",
  "mcp_url": "https://api.corespeed.io/mcp",
  "status": "disconnected",
  "accounts": []
}
```

**404 Not Found** — Unknown id or not offered here

Both 404 cases answer with the gateway's catch-all shape — the nested envelope
and a `message` listing the gateway's supported surfaces. A connector not
offered on this environment returns exactly this, so the response carries no
hint that the id is one CoreSpeed implements.

```json
{
  "error": {
    "type": "not_found",
    "code": "endpoint_not_found",
    "message": "Unknown endpoint /connectors/nope. Supported surfaces: …"
  }
}
```

**402 Payment Required** — No active organization

The credential authenticated but resolves to no active organization, so there is
no boundary to read connector state inside.

```json
{
  "error": {
    "type": "payment_required",
    "code": "no_active_org",
    "message": "No organization resolved for this request. Open https://app.corespeed.io in a browser once to finish setup, then sign in again so your client picks up the new workspace."
  }
}
```